Reputation: 68648
Why doesn't the follow C++11 program compile?
template<template<typename> class X, typename Y> struct C;
template<template<typename> class X, typename Z> struct C<X, X<Z>> {};
template<typename T> using A = T*;
int main()
{
C<A, A<int>> c;
}
The error is:
aggregate ‘C<A, int*> c’ has incomplete type and cannot be defined
Why doesn't the partial specialization of C
match C<A, A<int>>
?
Upvotes: 2
Views: 250
Reputation:
I think that 14.5.7 Alias templates:
When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template.
would apply, so X<Z>
would be interpreted as Z*
as soon as X
is known to be an alias template. The syntax for a partial specialisation does indeed use the template-id grammar rule. However, template argument substitution takes place as the last step in template argument deduction, only once all template arguments have been deduced.
14.5.5.1 Matching of class template partial specializations [temp.class.spec.match]
2 A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list (14.8.2).
14.8.2 Template argument deduction [temp.deduct]
5 When all template arguments have been deduced or obtained from default template arguments, all uses of template parameters in the template parameter list of the template and the function type are replaced with the corresponding deduced or default argument values.
Without template argument substitution of X
, Z
cannot be deduced. So, the specialisation does not match.
Upvotes: 4
Reputation: 137810
A
is an alias template, and it essentially specializes to a typedef-name. A<int>
is like a typedef for int *
.
C<A, A<int>>
is the same as C<A, int *>
. The parameter X
gets A
and the parameter Y
gets int *
. To deduce that Z
in the partial specialization should be int
, the compiler would have to inspect inside the alias definition. That is not how aliases work. The definition is a non-deduced context, even if substituting the alias definition into its indirect use X<Z>
in the partial specialization would produce a deduced context. Moreover, that deduction would need to be done speculatively to determine that A
can even be X
in the first place. Tackling this problem would be a huge burden of complexity.
As you mentioned on the std-discussion list, "An alias template name is never deduced."
Upvotes: 1
Reputation: 119877
A<int>
is int
, so C<A, A<int>>
is C<A, int>
. The specialization cannot match what you want because it cannot see A<int>
.
Upvotes: 1