重载函数的地址

来自cppreference.com
< cpp‎ | language

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

1) 对象或引用声明中的初始化器
2) 在赋值运算符的右侧
3) 作为函数调用参数
4) 作为用户定义运算符参数
5) return 语句
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]