C++模板函数优先级

Ash*_*hot 21 c++ templates function overload-resolution

#include <iostream>

template <class U, class T>
void foo(U&, T&)
{
    std::cout << "first";
}

template <class T>
void foo(int&, const T&)
{
    std::cout << "second";
}

int main()
{
    int a;
    double g = 2.;
    foo(a, g); // prints "first"

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

要调用第二个foo重载,编译器只需执行一次模板类型推导,但对于第一次重载,它需要执行两次.你能解释为什么第一次超载被调用了吗?

Bar*_*rry 18

过载分辨率分多步完成.

首先,通过名称查找,我们选择可行的候选人列表.在这种情况下,即:

template <class U, class T>
void foo(U&, T&);            // with U = int, T = double

template <class T>
void foo(int&, const T&)     // with T = double
Run Code Online (Sandbox Code Playgroud)

接下来,我们确定每个可行候选者的每个参数所需的转换序列.这是[over.ics.rank]:

如果[...] 标准转换序列S1是比标准转换序列更好的转换序列 S2

  • S1是S2的正确子序列(比较13.3.3.1.1定义的规范形式的转换序列,不包括任何左值变换;身份转换序列被认为是任何非同一性转换序列的子序列),或者,如果不是那个,
  • S1的等级优于S2的等级,或者S1和S2具有相同的等级,并且可以通过下面段落中的规则区分,或者,如果不是,

对于第一次调用,转换序列是(Identity,Identity).对于第二次调用,转换序列是(Identity,Identity).所以我们在那里是平等的.这两个要点都没有区分这两个要求.所以我们继续前进.

  • S1和S2是引用绑定(8.5.3),并且都不引用没有ref-qualifier声明的非静态成员函数的隐式对象参数,S1将rvalue引用绑定到rvalue,S2绑定左值引用.

无关紧要.

  • S1和S2是引用绑定(8.5.3),S1将左值引用绑定到函数左值,S2将右值引用绑定到函数左值.

不.

  • S1和S2的区别仅在于它们的资格转换并且分别产生类似的类型T1和T2(4.4),并且类型T1的cv资格特征签名是T2类型的cv资格特征的适当子集.

资格转换是一个指针的事情,不.

  • S1和S2是引用绑定(8.5.3),引用引用的类型除了顶级cv限定符之外是相同的类型,并且S2引用的引用所引用的类型比cv更合格.由S1初始化的引用所引用的类型.

在这种情况下,第一个重载采用第二个参数,double&而第二个重载采用a const double&.前者是少品种比后者-qualified,所以我们在这里停止-喜欢foo(U&,T&).

只有在确定哪个转换序列更好的步骤之后,我们才能进入更专业的模板首选的步骤.[over.match.best]中的完整规则排序是:

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

  • 对于某些参数j,ICSj(F1)是比ICSj(F2)更好的转换序列,或者,如果不是,

这就是我们刚刚经历的事情.

  • 上下文是用户定义的转换初始化[...]
  • 上下文是通过转换函数初始化直接引用绑定[...]
  • F1不是函数模板特化,F2是函数模板特化,或者,如果不是,
  • F1和F2是功能模板特化,根据14.5.6.2中描述的偏序规则,F1的功能模板比F2的模板更专业.

这就是我们选择的原因foo(U&, T&).const但是,如果删除了,则两个转换序列在所有步骤中都是相同的 - 所以在这一点上,更专业的模板(foo(int&, T&))将获胜.

请注意,更专业的是 确定最佳候选人的最后一种机制.这是决胜局的最后决定.

另请注意,模板扣除的数量无关紧要.它可以不管在过载是一个模板和过载这不是一个模板之间进行选择-但它不会在具有过载之间选择无关紧要X模板参数和具有过载Y> X模板参数.


Pio*_*iwa 7

你在第二个函数中声明第二个参数是const.下面的应用修正示例调用第二个示例:

#include <iostream>

template <class U, class T>
void foo(U&, T&)
{
    std::cout << "first";
}

template <class T>
void foo(int&, T&)
{
    std::cout << "second";
}

int main()
{
    int a;
    double g = 2.;
    foo(a, g);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

另一方面,当您显式声明第二个参数constmain(),应用程序将按照预期在上面的示例中调用第二个函数:

#include <iostream>

template <class U, class T>
void foo(U&, T&)
{
    std::cout << "first";
}

template <class T>
void foo(int&, const T&)
{
    std::cout << "second";
}

int main()
{
    int a;
    const double g = 2.;
    foo(a, g);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)