【问题标题】:Why is template overload a better match than a simple conversion?为什么模板重载比简单的转换更好?
【发布时间】:2015-03-29 01:51:19
【问题描述】:
#include <iostream>
using namespace std;

template<typename T>
void func(T t)  { std::cout << "matched template\n"; }

void func(long x) { std::cout << "matched long\n"; }

int main()
{  
    func(0);
}

输出:

matched template

在其他情况下,当重载解析可能不明确时,首选非模板函数,为什么这个不同?

【问题讨论】:

  • 0int,而不是 long。模板函数可以提供分辨率而无需转换。我猜:)
  • FWIW,我最近又看了STL's overload resolution video,忘了它有多好。
  • 这是在询问规则为何如此的原因,还是只是来自说明规则的标准的信息?
  • “当重载决议可能不明确时,首选非模板函数” - 当然。但void f(int); void f(long); f(0); 中没有任何含糊之处。
  • @NeilKirk 都很棒:)

标签: c++ templates overload-resolution


【解决方案1】:

§13.3.3 [over.match.best]/p1-2:

1 定义ICSi(F)如下:

  • (1.1) [省略不适用的项目符号]
  • (1.2) 令ICSi(F) 表示将列表中第i 个参数转换为第i 个参数类型的隐式转换序列 可行的功能F。 13.3.3.1 定义隐式转换 序列和 13.3.3.2 定义了它对一个隐式的含义 转换序列是更好或更差的转换序列 转换顺序比另一个顺序。

鉴于这些定义,一个可行的函数F1 被定义为 如果所有参数都比另一个可行的函数F2 更好的函数 i, ICSi(F1) 不是比ICSi(F2) 差的转换序列, 然后

  • (1.3) 对于某些参数jICSj(F1) 是比ICSj(F2) 更好的转换顺序,或者,如果不是这样,

  • [省略了几个不适用的项目符号]

  • (1.6) F1 不是函数模板特化,F2 是函数模板特化,或者,如果不是,
  • [省略不适用的项目符号]

2 如果只有一个可行的函数是更好的函数 比所有其他可行的功能,那么它是由 重载决议;否则调用格式不正确。

§13.3.3.2 [over.ics.rank],第 3.2 条:

  • (3.2) 标准转换序列S1 是比标准转换序列S2 更好的转换序列 if
    • (3.2.1) S1S2 的适当子序列(比较由 13.3.3.1.1 定义的规范形式的转换序列,不包括任何 左值变换;考虑恒等转换序列 作为任何非身份转换序列的子序列)

令 F1 = func&lt;int&gt;(int), F2 = func(long),只有一个参数,类型为 int。所以ICS1(F1)是身份转换; ICS1(F2) 是从intlong 的整数转换;因此,根据 [over.ics.rank]/3.2.1,ICS1(F1) 是比ICS1(F2) 更好的转换序列(因此根据定义,它并不比ICS1(F2) 差)。因此,根据 [over.match.best] 中的第 1.3 条,F1 优于 F2。项目符号 1.6 中的模板/非模板决胜局根本不会发挥作用。

【讨论】:

  • 为这项努力点赞!这时候我真的无法解析所有的标准 :)
【解决方案2】:

隐式转换可能会带来开销,并且可能出乎程序员的意料,因此在我看来,标准选择不涉及转换的选项是合乎逻辑的。

【讨论】:

    【解决方案3】:

    我认为(但不是绝对确定,即不知道标准中的确切引用,尽管会尝试查找)如果参数与非模板的类型不完全匹配,那么模板将开始吧。或者,换句话说,转化次数趋于最小化。例如,在

    f(long)
    

    对比

    template <typename T>
    f(T)
    

    f(long) 需要转换(从0,例如int,到long),而模板不需要(当然)转换。

    经过@T.C.的一些挖掘和帮助,标准的相关部分是Sec。 13.3.3,[over.match.best]。这是一个相当长的技术部分,但基本上是说具有Identity 转换的函数优于非Identity 转换。

    【讨论】:

    • 发生模板参数推导,最终得到(模板)f(int)f(long)。当(模板)f(int)f(int) 之类的模棱两可时,不推荐使用模板。
    • @chris,你最终将f(0) 推导出为f(int),然后f(long) 的另一个重载。现在,f(int) 是更好的匹配,因为 0int 文字,但需要转换为 long
    • 是的,只是为了更容易找到相关的标准。
    • 从 [over.match.best] 开始。
    猜你喜欢
    • 1970-01-01
    • 2011-05-12
    • 1970-01-01
    • 2015-07-08
    • 2013-02-18
    • 2020-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多