什么时候可以在私有成员类型上专门化模板?

Dan*_*Dan 7 c++ templates

鉴于这些定义

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)

什么时候发生这种情况,除了公开这种类型之外还有解决方法吗?

Col*_*mbo 5

考虑CWG#182:

某些访问检查在显式实例化时被抑制.14.7.2 [temp.explicit]第8段说[...]我很惊讶类似的措辞不存在(我能找到)用于明确的专业化.我认为这两个案例应该在下面的例子中等效处理(即应该允许专业化).

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
Run Code Online (Sandbox Code Playgroud)

[...]

理由(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显示不正确的两个案例:

模板参数的名称可以在用作模板参数的位置访问.