鉴于这些定义
template<class T> class foo {};
template<class T> class foo1 { static int i; };
class bar { class baz {}; };
Run Code Online (Sandbox Code Playgroud)
我很惊讶地看到这个编译
template<>
class foo<bar::baz> {};
Run Code Online (Sandbox Code Playgroud)
但这失败了,错误 'class bar::baz' is private
template<>
int foo1<bar::baz>::i = 42;
Run Code Online (Sandbox Code Playgroud)
什么时候发生这种情况,除了公开这种类型之外还有解决方法吗?
考虑CWG#182:
某些访问检查在显式实例化时被抑制.14.7.2 [temp.explicit]第8段说[...]我很惊讶类似的措辞不存在(我能找到)用于明确的专业化.我认为这两个案例应该在下面的例子中等效处理(即应该允许专业化).
Run Code Online (Sandbox Code Playgroud)template <class T> struct C { void f(); void g(); }; template <class T> void C<T>::f(){} template <class T> void C<T>::g(){} class A { class B {}; void f(); }; template void C<A::B>::f(); // okay template <> void C<A::B>::g(); // error - A::B inaccessible[...]
理由(2002年10月):
我们重新考虑了这一点,并决定两种情况(显式专业化和显式实例化)之间的差异是恰当的.访问规则有时会在必要时进行弯曲以允许命名,例如在显式实例化中,但显式特化不仅需要命名实体,还需要在某处提供定义.
GCC和Clang确实拒绝了所示示例的最后一行,这显然是 - 不一致的行为,对于类模板的相应显式特化,它们不会发出错误消息:
template <class> struct T {
void g();
};
class A { class B; class C; };
template <> struct T<A::B>; // Ok
template <> void T<A::C>::g(); // Error
Run Code Online (Sandbox Code Playgroud)
演示.因此,我会在这里讨论并告诉你§14.3/ 3显示不正确的两个案例:
模板参数的名称可以在用作模板参数的位置访问.