【问题标题】:overload resolution of template function with auto模板函数的自动重载解析
【发布时间】:2017-05-01 18:03:09
【问题描述】:

具有以下 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 和 2 不是违反 ODR 吗?
  • 如果“auto”被翻译成“int”,那么#1 和#2 是一样的,是吗?不是首选候选人。 Clang 似乎认为 #2 比 #1 更专业,而 #1 和 #3 是相同的专业化;再次模棱两可的选择。我会说 gcc 是对的,而 Clang 是错的,因为“auto”不应该参与重载决议。
  • @user657267 返回类型是函数模板签名的一部分。上面的声明提供了不同的declared返回类型,所以签名不同。实际返回类型是否一致是无关紧要的。
  • 好问题。 +1

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


【解决方案1】:

按照[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的函数类型不包含任何参与推演的模板参数,因此通过核心问题1391的解析引入的[temp.deduct.partial]/4的添加,它们对应的Ps没有用于确定排序。 @bogdan 解释了 here 为什么该解决方案有问题;最重要的是,排序只会对 #1 和 #2 产生歧义。

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

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

[temp.deduct.type]/8 element 9 (T()),如果你好奇的话。

【讨论】:

  • 起首部分。非常有意思。你知道标准,无论如何它让我有点害怕...... :-) +1
猜你喜欢
  • 1970-01-01
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多