使用auto重载模板函数的分辨率

Jar*_*d42 9 c++ templates overloading language-lawyer c++14

随着3次超载

template <class T> auto foo() { return 1; }
template <class T> int  foo() { return 2; }
template <class T> T    foo() { return 3; }
Run Code Online (Sandbox Code Playgroud)

以下是不良形成的?

static_cast<int(*)()>(&foo<int>)();
Run Code Online (Sandbox Code Playgroud)

Clang选择重载#2,而gcc无法编译(Demo)

当删除过载#1时,两者都同意选择过载#2(演示).

当删除重载#2时,gcc选择重载#1并且clang无法编译(Demo)

Col*_*mbo 8

根据[over.over]/2,我们执行模板参数推导.这将成功实现所有三个重载:在第一个重载中,记住[temp.deduct.funcaddr]/2:

函数模板的返回类型中的占位符类型(7.1.7.4)是非推导的上下文.如果模板参数推导对于这样的函数成功,则返回类型是从函数体的实例化确定的.

由于推导将成功(假设所有模板参数都显式提供了参数),则返回类型推导为int.在第二种情况下,从提供参数开始,推论成功,在第三种情况下,将推T导出推论.

继续第4段,

如果选择了多个函数,F1则如果集合包含第二个函数模板特化,则消除任何给定的函数模板特化,其功能模板比F1根据14.5.6.2的部分排序规则的函数模板更专业化.在这种消除之后,如果有的话,应该保留一个选定的功能.

根据[temp.deduct.partial]/3,函数模板的函数类型用于部分排序.我们可以立即看到#1和#2的函数类型不包含任何参与演绎的模板参数,因此通过核心问题1391分辨率引入的[temp.deduct.partial]/4的加法,它们的对应s是不习惯确定订货.@bogdan 在这里解释为什么这个解决方案有问题; 最重要的是,排序只会产生#1和#2的歧义.P

也就是说,根据当前(可能是有缺陷的)措辞,转换在所有情况下都是错误的.如果对非依赖/推导参数对修正了部分排序,

  • 情况1和3是不明确的,因为对于两个非依赖函数类型(#1和#2的函数类型),没有排序对.
  • 案例2中的接受行为是正确的(如预期的那样).

[temp.deduct.type]/8 element 9(T()),以防您好奇.