Consider CWG # 182 :
Some access checks are suppressed by explicit instantiations. 14.7.2 [temp.explicit] in clause 8 says [...] I was surprised that such a formulation does not exist (what I can find) for explicit specializations. I believe that these two cases should be handled equivalently in the example below (i.e. that specialization should be allowed).
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();
[...]
Justification (October 2002) :
We reviewed this and decided that the difference between the two cases (explicit specialization and explicit implementation) is appropriate. Access rules are sometimes bent when necessary to allow you to name something, as in an explicit instantiation, but obviously specialization requires not only the name of the object, but also the provision of a definition somewhere.
GCC and Clang really reject the last line of the example, that apparently inconsistent behavior, as well as for the corresponding explicit specialization of the class template, they do not give an error message:
template <class> struct T { void g(); }; class A { class B; class C; }; template <> struct T<A::B>;
Demo Therefore, I will go out on a limb and name both cases that you showed poorly formed in Β§14.3 / 3:
The name of the template argument must be available at the point where it is used as the template argument.
Columbo
source share