重载决议的步骤

重载解析的步骤是:

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

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

    void f(char);          // (1)
    void f(int ) = delete; // (2)
    void f();              // (3)
    void f(int& );         // (4)
    
    f(4); // 1,2 are viable (even though 2 is deleted!) 
          // 3 is not viable because the argument lists don't match
          // 4 is not viable because we cannot bind a temporary to 
          //     a non-const lvalue reference
    
  3. 选择最有可行的候选人。如果 F1 中每个参数的隐式转换序列不比 F2 中相应的隐式转换序列差,则可行函数 F1 是比另一个可行函数 F2 更好的函数,并且……:

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

    void f(int );  // (1)
    void f(char ); // (2)
    
    f(4);  // call (1), better conversion sequence
    

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

    struct A 
    {
        operator int();
        operator double();
    } a;
    
    int i = a; // a.operator int() is better than a.operator double() and a conversion
    float f = a; // ambiguous
    

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

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

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

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

    3.5。F1F2 都是功能模板专业化,但 F1F2 更专业。

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

这里的订购很重要。在模板与非模板检查之前进行更好的转换序列检查。这导致转发引用上的重载常见错误:

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

A a;
A b(a); // calls #2!
        // #1 is not a template but #2 resolves to
        // A(A& ), which is a less cv-qualified reference than #1
        // which makes it a better implicit conversion sequence

如果最后没有单一的最佳可行候选人,那么这个调用是不明确的:

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

f(42); // error: ambiguous