为什么不跟随C ++ 11程序编译?
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;
}
错误是:
aggregate ‘C<A, int*> c’ has incomplete type and cannot be defined
为什么C
的部分专业化不匹配C<A, A<int>>
?
答案 0 :(得分:4)
我认为 14.5.7 Alias模板:
当 template-id 引用别名模板的特化时,它等同于通过将 template-arguments 替换为 type-id 中的> template-parameters 。
将适用,因此只要X<Z>
已知为别名模板,Z*
就会被解释为X
。部分特化的语法确实使用 template-id 语法规则。但是,模板参数替换是模板参数推导的最后一步,只有在推导出所有模板参数后才会发生。
14.5.5.1匹配类模板部分特化[temp.class.spec.match]
2如果可以从实际模板参数列表(14.8.2)推导出部分特化的模板参数,则部分特化匹配给定的实际模板参数列表。
14.8.2模板参数推断[temp.deduct]
5当从默认模板参数推断或获得所有模板参数时,模板的模板参数列表中的模板参数的所有使用和函数类型都将替换为相应的推导或默认参数值。
如果没有X
的模板参数替换,则无法推断出Z
。所以,专业化不匹配。
答案 1 :(得分:1)
A<int>
int
,因此C<A, A<int>>
C<A, int>
。专业化无法与您想要的匹配,因为它无法看到A<int>
。
答案 2 :(得分:1)
A
是别名模板,它主要专门用于typedef-name。 A<int>
就像int *
的typedef。
C<A, A<int>>
与C<A, int *>
相同。参数X
获取A
,参数Y
获得int *
。要推断部分特化中的Z
应为int
,编译器必须在别名定义内部进行检查。这不是别名的工作方式。该定义是一个非推导的上下文,即使将别名定义替换为部分特化中的间接使用X<Z>
也会产生推导的上下文。此外,这种推论需要以推测方式进行,以确定A
首先可以X
。解决这个问题将是一个巨大的复杂负担。
正如您在std讨论列表中提到的那样,“永远不会推断出别名模板名称。”