我对下面部分特化的 GCC 错误输出感到困惑。
// Primary
template<class T, class U1, class U2, class... Us>
struct S{};
// #1
template<class T, class... Us>
struct S<T, T, T, Us...>{};
// #2
template<class T, class U, class... Us>
struct S<T, T, U, Us...>{};
// #3
template<class T, class U, class... Us>
struct S<T, U, T, Us...>{};
// #4
template<class T, class U1, class U2, class U3, class... Us>
struct S<T, U1, U2, U3, Us...>{};
当我尝试调用S<int, int, long, float, double>
时编译器表示无法决定选择 #2 和 #4 中的哪一个作为实例化。但我认为#2 在这方面比#4 更专业,所以它应该做出决定。
我的原因如下:
当#2和#4都可以被调用时,即模板参数的数量不少于4个,从方式介绍here ,我们可以为 #2 定义一个虚构函数,即
template<class T, class U, class... Us>
f<X<T, T, U, Us...>); // #A
还有一个用于#4
template<class T, class U1, class U2, class U3, class... Us>
f<X<T, U1, U2, U3, Us...>); // #B
然后,#A 来自 #B( void(X<T, T, U, aUs...>)
来自 void(X<U1, U2, U3, U4, bUs...>)
):
-
P1=T, A1=U1: T=U1
, -
P2=T, A2=U2: T=U2: fails
;
#A 中的 #B(void(X<T, U1, U2, U3, bUs...>)
中的 void(X<U1, U2, U3, aUs...>)
):
-
P1=T, A1=U1
, -
P2=U1, A2=U2
, -
P3=U2, A3=U3
, -
P4=U3, A4=<aUs...>[0]
(<aUs...>
在本例中不为空), -
P5=Us..., A5=<aUs...>[1,]
(<aUs...>[1,]
现在可能为空)。
这样#A中的#B就成功执行了,那么我认为#2比#4更专业,所以应该选择#2。
如果GCC是对的(最有可能),我想知道我上面的陈述哪一部分出了问题。非常感谢。
可以找到一个实例 here .
最佳答案
概念上两者都不是#2
也不#4
更专业,因为有 A
的模板参数列表这样#2
是可行的,但不是#4
,以及 #4
的此类集合是可行的,但是#2
不是。
在您的正式分析中,一切看起来都是正确的,除了
P4=U3, A4=<aUs...>[0]
(<aUs...>
is not empty in this case),
推导失败,因为您需要实际比较所有<aUs...>
作为单个(想象的)模板参数 A4
与P4
相匹配并根据[temp.deduct.type]#9.2 ,因为它源自包扩展,A4
然后,应该在参数的模板参数列表中没有对应的元素,或者对应于参数的模板参数列表中也源自包扩展的元素,其中 P4
不会(因为它只是 U3
)。
关于c++ - 澄清部分模板特化的歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73595156/