使用可变参数模板的功能模板重载:英特尔c ++编译器版本18产生的结果与其他编译器不同。英特尔错了吗?

时间:2019-05-02 10:06:02

标签: c++ templates language-lawyer variadic-templates

请考虑以下代码段:

template<typename T, template<typename, typename ...> class A, typename ... Ts>
int a(A<T, Ts...> arg){
  return 1; // Overload #1
}

template<typename A>
int a(A arg) {
  return 2;  // Overload #2
}

template<typename T>
struct S{};

int main() {
  return a(S<int>());
}

在使用模板类的实例调用函数a时,我希望编译器选择更特殊的函数重载#1。根据{{​​3}},在版本17之前的clang,gcc和intel实际上确实选择了#1重载。相反,后来的intel编译器版本(18和19)则选择重载#2。

代码定义不正确还是最新的intel编译器版本错误?

1 个答案:

答案 0 :(得分:2)

icc 19.01上的以下fails to call a()

template<template<typename, typename ...> class A, typename T, typename ... Ts>
int a(A<T, Ts...> arg){
    return 1;
}

template<typename T>
struct S{};

int foo()
{
    return a(S<int>());
}

它根本不能认为a()是候选者,这就是为什么重载在问题上有所不同的原因。

C++17 draft说:

(其中P是template-template参数,A是实例化参数)

  

17.3.3 模板模板参数

     
      
  1. 当P至少与P一样专门时,template-argument匹配template-parameterP。   模板参数A。如果P包含参数包,则如果A的每个模板参数都与P相匹配   匹配P模板头中的相应模板参数。
  2.   

到目前为止,<int参数头与参数头<T匹配。

  

两个模板参数匹配   如果它们属于同一类型(类型,非类型,模板),那么对于非类型模板参数,其类型为   等价的(17.6.6.1),,对于模板模板参数,其每个对应的模板参数   递归匹配。

仍然看起来不错,intT匹配。

  

当P的模板头包含模板参数包(17.6.3)时,该模板   参数包将与模板头中的零个或多个模板参数或模板参数包匹配   A的类型和形式与P中的模板参数包相同(忽略那些模板   参数是模板参数包。

这很难解析,但是对我来说似乎还可以。据我了解,编译器应该已将参数与template-template参数匹配。它明确地谈论零个或多个,这里我们零。