gcc vs. clang,msvc和icc:这个函数调用不明确吗?

时间:2016-09-02 06:57:12

标签: c++ c++11 language-lawyer partial-ordering

我能得到的所有编译器都同意这很好:

template <typename Check, typename... T>
auto foo(Check, T...) -> void;

template <typename... T>
auto foo(int, T...) -> void;

int main()
{
  foo(7, "");
}

但是,根据gcc,以下代码(具有无法从函数参数推导出的前导模板参数)是不明确的:

template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;

template <typename X, typename... T>
auto bar(int, T...) -> void;

int main()
{
  bar<void>(7, ""); // ambiguous according to gcc
  bar<void>(7);     // just fine
}

另一方面,clang,msvc和icc对此非常满意。

哪种编译器是对的?

参考标准偏好的各个部分。

2 个答案:

答案 0 :(得分:4)

这是core issue 200

  

模板函数的部分排序如何描述   在14.5.6.2中确定[temp.func.order]第3-5段没有   任何非弱化模板参数的规定。例如,   以下代码中的函数调用是模糊的,即使是一个   模板“显然”比另一个更专业:

template <class T> T f(int);
template <class T, class U> T f(U);
void g() {
    f<int>(1);
}
     

原因是函数参数列表都不允许推导出模板参数T;扣除都失败了,所以都没有   模板被认为比其他模板更专业   函数调用含糊不清。

core issue 214的解决方案,[temp.deduct.partial]/11引入{{3}}:

  

在大多数情况下,所有模板参数必须具有值才能使演绎成功,但是对于部分排序目的,模板参数可以保持不带值,前提是它不用于用于部分排序的类型< /强>

显然,一旦打包,GCC对这一措辞的实施就会出现问题。

答案 1 :(得分:0)

恕我直言,我认为海湾合作委员会错了,CLANG在这里是正确的。我将尝试在下面证明我的主张:

根据标准§14.8.3/ p1重载决议[temp.over](强调我的

  

函数模板可以通过(非模板)重载   其名称或其他功能模板的功能   名称。当写入对该名称的调用时(显式或隐式)   使用运算符表示法),模板参数推导(14.8.2)   并检查任何显式模板参数(14.3)   为每个函数模板找到模板参数值(如果   any)可以与该函数模板一起使用来实例化a   可以通过调用调用的函数模板特化   参数。对于每个函数模板,如果参数推论和   检查成功,模板参数(推断和/或显式)   用于合成单个函数模板的声明   添加到候选函数中的特化   用于重载解析。如果,对于给定的函数模板,   参数推导失败或合成的函数模板   专业化将是不正确的,没有这样的功能被添加到   该模板的候选函数集。完整的一套   候选函数包括所有合成声明和所有   非模板重载函数的同名。该   合成声明被视为与...中的任何其他函数一样   超出分辨率的剩余部分,除非明确指出   13.3.3。 144

     

[实施例:

template<class T> T max(T a, T b) { return a>b?a:b; }
void f(int a, int b, char c, char d) {
int m1 = max(a,b); // max(int a, int b)
char m2 = max(c,d); // max(char a, char b)
int m3 = max(a,c); // error: cannot generate max(int,char)
}
     

144)函数模板特化的参数包含   没有模板参数类型。推断出允许的转换集   参数是有限的,因为参数推导过程产生   功能模板,其参数与呼叫匹配   参数完全或仅在可以被桥接的方式上有所不同   允许有限的转换。未推断的参数允许完整   转换范围。另请注意,13.3.3指定了a   非模板函数将优先于模板   如果两个功能在其他方面同样好,则专业化   过度匹配的候选人。

从上面我们得到了显式模板参数将被检查,如果检查成功,那么将用于合成将被添加到候选函数以进行重载解析的特化。因此,您明确指定X的事实与该过程无关。

同样来自C ++标准§13.3.3/ p1.7最佳可行功能[over.match.best]

  

F1F2是函数模板特化和函数   F1的模板比F2的模板更专业   根据14.5.6.2中描述的偏序规则。

现在从§14.5.6.2/ p3函数模板的部分排序[temp.func.order] 我们得到的是,在部分排序参数包中也可以使用,所以这里也没问题。 / p>

现在:

template <typename X, typename... T>
auto bar(int, T...) -> void;

比以下更专业:

template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;

因此致电:

bar<void>(7, "");

不含糊。

基于以上所述,我认为这是一个GCC错误。