C++ 重载解析步骤

示例

解决过载的步骤为:

  1. 通过名称查找查找候选函数。不合格的调用将执行常规的不合格查询以及依赖于参数的查询(如果适用)。

  2. 将候选函数集过滤为一组可行函数。一个可行的函数,在调用该函数的参数与该函数采用的参数之间存在隐式转换序列。

    void f(char);          // (1)
    void f(int ) = delete; // (2)
    void f();              // (3)
    void f(int& );         // (4)
    f(4); // 1,2是可行的(即使2被删除了!)
         // 3不可行,因为参数列表不匹配
         // 4是不可行的,因为我们不能将临时绑定到
         //     a non-const lvalue reference
  3. 选择最佳可行的候选人。一个可行的功能F1比另一个可行的功能更好的功能F2,如果在每个参数的隐式转换序列F1并不比相应的隐式转换序列糟糕F2,和...:

    3.1。对于某些参数,该参数中的隐式转换F1顺序比F2或中的该参数的转换顺序更好。

    void f(int );  // (1)
    void f(char ); // (2)
    f(4);  // 调用(1),转换顺序更好

    3.2。在用户定义的转换中,从返回F1到目标类型的标准转换顺序比F2或返回类型的标准转换顺序更好。

    struct A 
    {
       operator int();
       operator double();
    } a;
    int i = a; //a.operatorint()优于a.operatordouble()和转换
    float f = a; // 暧昧

    3.3。在直接引用绑定中,F1具有相同引用类型的F2不是,或者

    struct A 
    {
       operator X&();  // #1
       operator X&&(); // #2
    };
    A a;
    X& lx = a;  // 呼叫#1
    X&& rx = a; // 呼叫#2

    3.4。F1不是一个函数模板专业化,但F2是,或

    template <class T> void f(T ); // #1
    void f(int );                  // #2
    f(42); // 呼叫#2, the non-template

    3.5。F1和F2都是功能模板专长,但是F1比更加专业F2。

    template <class T> void f(T );  // #1
    template <class T> void f(T* ); // #2
    int* p;
    f(p); // 呼叫#2, more specialized

这里的顺序很重要。更好的转换顺序检查发生在模板检查与非模板检查之前。这会导致转发参考过载的常见错误:

struct A {
    A(A const& ); // #1
    
    template <class T>
    A(T&& );      // #2, not constrained
};

A a;
A b(a); // 呼叫#2!
        // #1 is not a template but #2 resolves to
        // A(A& ), which is a less cv-qualified reference than #1
        // 这使其成为更好的隐式转换序列

如果最后没有一个最佳可行的候选人,那电话就是模棱两可的:

void f(double ) { }
void f(float ) { }

f(42); // 错误:模棱两可