This question consists of two parts, marked (A) through ...ahem... (C).
template< unsigned a > struct Outer {
/*
(A) Provide a match if the template parameter of Inner is the same
as Outer. Do something different in the general case (not shown)
*/
template< unsigned b > struct Inner1;
template<> struct Inner1<a> { enum { value = a }; };
/*
(B) Same idea as (A), but we want an additional template parameter
*/
template< typename T, unsigned b > struct Inner2;
template< typename T > struct Inner2< T, a > { enum { value = a }; };
typedef Inner1<a> Result1;
typedef Inner2<int, a> Result2;
};
// (C) Alternative way of defining our specializations?
template< unsigned a > template<>
struct Outer<a>::template Inner1<a> {};
template< unsigned a > template< typename T >
struct Outer<a>::template Inner2<T, a> {};
void code() {
Outer<1>::Result1::value; // OK,
Outer<1>::Result2::value; // error C2027: use of undefined type 'Outer<1>::Inner2<int,1>'
}
Using Visual Studio 2013 or 2015, without language extensions, (A) and (B) compile successfully. (C) helpfully fails with fatal error C1001: An internal error has occurred in the compiler.
(A) Result1 is correctly selected to be the specialized template
(B) Result2 is not, resulting in the 'use of undefined type'.
I have read, though, that it is not OK to specialize a class template nested inside of a class template. Why has it worked here? If I want to provide this kind of behavior (matching on an outer template parameter) what better ways are there?