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

时间:2016-12-16 01:25:41

标签: c++ templates c++14 language-lawyer overloading

以下3次重载

template <class T> auto foo() { return 1; }
template <class T> int  foo() { return 2; }
template <class T> T    foo() { return 3; }

以下是不良形成的?

static_cast<int(*)()>(&foo<int>)();

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

当删除重载#1时,两者都同意选择重载#2(Demo)。

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

1 个答案:

答案 0 :(得分:8)

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

  

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

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

继续paragraph 4

  

如果选择了多个功能,则任何给定的功能   如果集合包含,则消除函数模板特化F1   第二个函数模板专业化,其功能模板是   比F1的功能模板更专业   14.5.6.2的部分排序规则。 此类淘汰后,如果有,将保留一个选定的功能。

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

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

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

[temp.deduct.type]/8元素9(P),以防你好奇。