c++ - 澄清部分模板特化的歧义

标签 c++ variadic-templates specialization

我对下面部分特化的 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...>作为单个(想象的)模板参数 A4P4相匹配并根据[temp.deduct.type]#9.2 ,因为它源自包扩展,A4然后,应该在参数的模板参数列表中没有对应的元素,或者对应于参数的模板参数列表中也源自包扩展的元素,其中 P4不会(因为它只是 U3 )。

关于c++ - 澄清部分模板特化的歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73595156/

相关文章:

c++ - 为什么 Unicode 字符 θ 在 POSTGRESQL 中不受支持

c++ - 为什么我不能在头文件中定义全局函数?

c++ - 并行算法寻找K个最近点

c++ - 使图形发光/光晕

c++ - std::visit 的 C++17 示例中令人困惑的模板

c++ - 如何访问可变 lambda 函数参数

c++ - 模板函数参数中的自动模板特化

c++ - 不能将 typeof(std::endl) 作为模板参数?

c++ - 基于整数类型 "signed-ness"的部分模板特化?

c++ - 固定值的模板特化