C++关于模板专用化和命名空间限定的规则是什么?我有一些代码可以归结为以下内容,这让我意识到我不理解C++关于模板专业化初始化的规则。首先,在我看来,g::F<>
的特殊化甚至被允许在h
内部,这似乎很奇怪,但鉴于此,我不知道为什么事情会这样。
namespace g {
struct N {
N(char c):c_(c){}
char c_;
};
template <typename V>
struct F {
static N n_s; // <-- want to initialize these for specializations
};
namespace h {
struct X { static constexpr char k{'x'}; };
template <> N F<char>::n_s{h::X::k}; // OK
template <> N F<int>::n_s{X::k}; // fails on "‘X’ not declared"
}
} // namespace g
// Seems weirdest to me. N and F need full qualifications but X doesn't.
template <> g::N g::F<float>::n_s{h::X::k}; // OK also!
最后一个实例化/初始化,其中模板静态成员初始化器推断g
命名空间,使模板看起来就像初始化器的行为,就像它位于代码中与模板定义本身相同的位置。
规范中规定这种行为的规则是什么?(注意,这是在gcc 4.8.1上测试的,到目前为止看起来有点像一个bug…)
这里的主要困惑不是专业化,而是资格。让我们看看最后一个专门化(在全局命名空间中)来说明这一点:
template <> g::N g::F<float>::n_s{h::X::k};
当这一行开始时,您处于全局名称空间中。因此,g::N
必然是合格的,g::F<float>
也是合格的。
然而,当你通过了你所专门化的东西(即在n_s
之后),你现在就在你所专业化的东西的范围内,即g::F
内部。所有进一步的查找都是在此范围内完成的,因此x
必须限定为h::X
。
也就是说,虽然允许在包含原始名称空间的名称空间中进行专门化,但在嵌套名称空间(在您的情况下为h
)内进行专门化在我看来很奇怪,但这里的标准有点模糊,正如14.7.3/2中所说:"应在包含专门化模板的名称空间内声明显式专门化。">
全局名称空间包含F
,所以这很好,g
也是如此。h
不包含F
,但h
在g
内,因此专业化也在g
内,这在技术上使得这很好。然而,通过这种推理,你可以在任何地方专门化一个模板,因为你总是在全局命名空间中,它包含了所有内容。所以我非常确信GCC在这里的行为过于宽容,而且是一个错误。您也应该在其他编译器中尝试一下,然后根据标准提交一个bug,或者可能是一个缺陷报告。
In:
template <> N F<int>::n_s{X::k}; // fails on "‘X’ not declared"
它失败是因为与F<int>::n_s
关联的命名空间是g
,而X
是在g::h
中声明的。这就是为什么你需要把它拼写成h::F<int>::n_s
。