Your code is correct; out-of-class implicitly instantiated class template member class template partial specializations are intended to be allowed by the Standard, as long as they are defined early enough.
First, let's try for a minimal example - noting by the way that there's nothing here that requires C++11:
template<class T> struct A {
template<class T2> struct B { };
};
// implicitly instantiated class template member class template partial specialization
template<> template<class T2>
struct A<short>::B<T2*> { };
A<short>::B<int*> absip; // uses partial specialization?
As noted elsewhere MSVC and ICC use the partial specialization as expected; clang selects the partial specialization but messes up its type parameters, aliasing T2
to short
instead of int
; and gcc ignores the partial specialization entirely.
Why out-of-class implicitly instantiated class template member class template partial specialization is allowed
Put simply, none of the language that permits other forms of class template member class template definitions excludes out-of-class implicitly instantiated class template member class template partial specialization. In [temp.mem], we have:
1 - A template can be declared within a class or class template; such a template is called a member template. A
member template can be defined within or outside its class definition or class template definition. [...]
A class template partial specialization is a template declaration ([temp.class.spec]/1). In the same paragraph, there is an example of out-of-class nonspecialized class template member class template partial specialization ([temp.class.spec]/5):
template<class T> struct A {
struct C {
template<class T2> struct B { };
};
};
// partial specialization of A<T>::C::B<T2>
template<class T> template<class T2>
struct A<T>::C::B<T2*> { };
A<short>::C::B<int*> absip; // uses partial specialization
There is nothing here to indicate that the enclosing scope cannot be an implicit specialization of the enclosing class template.
Similarly, there are examples of in-class class template member class template partial specialization and out-of-class implicitly instantiated class template member class template full specialization ([temp.class.spec.mfunc]/2):
template<class T> struct A {
template<class T2> struct B {}; // #1
template<class T2> struct B<T2*> {}; // #2
};
template<> template<class T2> struct A<short>::B {}; // #3
A<char>::B<int*> abcip; // uses #2
A<short>::B<int*> absip; // uses #3
A<char>::B<int> abci; // uses #1
(clang (as of 3.7.0-svn235195) gets the second example wrong; it selects #2 instead of #3 for absip
.)
While this does not explicitly mention out-of-class implicitly instantiated class template member class template partial specialization, it does not exclude it either; the reason it isn't here is that it's irrelevant for the particular point being made, which is about which primary template or partial template specializations are considered for a particular specialization.
Per [temp.class.spec]:
6 - [...] when the primary
template name is used, any previously-declared partial specializations of the primary template are also
considered.
In the above minimal example, A<short>::B<T2*>
is a partial specialization of the primary template A<short>::B
and so should be considered.
Why it might not be allowed
In other discussion we've seen mention that implicit instantiation (of the enclosing class template) could result in implicit instantiation of the definition of the primary template specialization to take place, resulting in an ill-formed program NDR i.e. UB; [templ.expl.spec]:
6 - If a template, a member template or a member of a class template is explicitly specialized then that specialization
shall be declared before the first use of that specialization that would cause an implicit instantiation
to take place, in every translation unit in which such a use occurs; no diagnostic is required. [...]
However, here the class template member class template is not used before it is instantiated.
What other people think
In DR1755 (active), the example given is:
template<typename A> struct X { template<typename B> struct Y; };
template struct X<int>;
template<typename A> template<typename B> struct X<A>::Y<B*> { int n; };
int k = X<int>::Y<int*>().n;
This is considered problematic only from the point of view of the existence of the second line instantiating the enclosing class. There was no suggestion from the submitter (Richard Smith) or from CWG that this might be invalid even in the absence of the second line.
In n4090, the example given is:
template<class T> struct A {
template<class U> struct B {int i; }; // #0
template<> struct B<float**> {int i2; }; // #1
// ...
};
// ...
template<> template<class U> // #6
struct A<char>::B<U*>{ int m; };
// ...
int a2 = A<char>::B<float**>{}.m; // Use #6 Not #1
Here the question raised is of precedence between an in-class class template member class template full specialization and an out-of-class class template instantiation member class template partial specialization; there is no suggestion that #6
would not be considered at all.
vargs<char, int>
is presumably due to the partial specialization not matching, for whatever reason.tag
...sounds like a bug. – Lenitydetails::outer<tag>::inner<tag>
during the process somewhere. Interesting, as I have no clue how a compiler can confuse those template arguments. – Asgardouter<tag>
withinner
's default and specialized forms, it produces the expected output: Coliru – Peggiechar
. – Hepzivargs<char>
and still get the same issue in clang and gcc – Countershadingouter<tag>::inner
before attempting to specialize it. See this on Ideone – Countershadingstd::vector<T>
for outer class seems to be completely impossible according to all the compilers. Though I guess seeing how this technique already super inconsistent I guess I will abstain from using it anyway. – Atharvaveda