重载函数的地址

来自cppreference.com
< cpp‎ | language

除了函数调用表达式之外,重载函数的名字还可以出现在下列 7 种发生重载决议的语境中:

1) 对象或引用声明中的初始化器
2) 赋值运算符的右侧
3) 作为函数调用的实参
4) 作为用户定义运算符的实参
5) return 语句
6) 显式转型static_cast 的实参
7) 非类型模板实参

在每个语境中,重载函数的名称可以前附取址运算符 & 并且可以被一组冗余的括号所环绕。

在所有这些语境中,从重载集中选择的函数,是其类型与目标所期待的函数指针、函数引用或成员函数指针类型相匹配的函数,目标分别为:被初始化的对象或引用,赋值的左侧,函数或运算符的形参,函数的返回类型,转型的目标类型,以及模板形参的类型。

函数的形参类型和返回类型必须与目标严格匹配,不考虑隐式转换(例如,在初始化指向返回基类指针的函数的指针时,不会选择返回派生类指针的函数)。

若函数名指名某个函数模板,则首先进行模板实参推导,而若其成功,则将生成一个单独的模板特化并添加到所要考虑的重载集合中。从集合中丢弃所有不满足其关联制约的函数。 (C++20 起)若集合中有多于一个函数与目标匹配,且至少一个函数是非模板,则从考虑中去除模板特化。对于任何一对非模板函数,其中之一比另一个更受制约,则从集合中丢弃受较少制约的函数。 (C++20 起)若所有剩余候选者都是模板特化,则当存在更特殊的模板特化时,移除较不特殊者。若在各项移除之后仍留有多于一个候选者,则程序非良构。

[编辑] 示例

int f(int) { return 1; }
int f(double) { return 2; }
 
void g( int(&f1)(int), int(*f2)(double) ) {}
 
template< int(*F)(int) >
struct Templ {};
 
struct Foo {
    int mf(int) { return 3; }
    int mf(double) { return 4; }
};
 
struct Emp {
    void operator<<(int (*)(double)) {}
};
 
int main()
{
    // 1. 初始化
    int (*pf)(double) = f; // 选择 int f(double)
    int (&rf)(int) = f; // 选择 int f(int)
    int (Foo::*mpf)(int) = &Foo::mf; // 选择 int mf(int)
 
    // 2. 赋值
    pf = nullptr;
    pf = &f; // 选择 int f(double)
 
    // 3. 函数实参
    g(f, f); // 为第一实参选择 int f(int)
             // 而为第二实参选择 int f(double)
 
    // 4. 用户定义运算符
    Emp{} << f; // 选择 int f(double)
 
    // 5. 返回值
    auto foo = []() -> int (*)(int) {
        return f; // 选择 int f(int)
    };
 
    // 6. 转型
    auto p = static_cast<int(*)(int)>(f); // 选择 int f(int)
 
    // 7. 模板实参
    Templ<f> t;  // selects int f(int)
}


[编辑] 引用

  • C++11 standard (ISO/IEC 14882:2011):
  • 13.4 Address of overloaded function [over.over]
  • C++98 standard (ISO/IEC 14882:1998):
  • 13.4 Address of overloaded function [over.over]