重载函数的地址

来自cppreference.com
< cpp‎ | language


 
 
 
 

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

语境目标
对象或引用声明中的初始化器被初始化的对象或引用
赋值运算符的右侧赋值运算符的左侧
作为函数调用的实参函数形参
作为用户定义运算符的实参运算符形参
return 语句函数的返回值
显式转换static_cast 的实参对应的转换
非类型模板实参对应的模板形参

在每个语境中,重载函数的名字可以前附取地址运算符 & 并且可以被一组冗余的圆括号包围。

如果目标类型包含占位类型,那么就会进行占位类型推导,并且在后续说明中会以推导出的类型作为目标类型。

(C++26 起)

选择函数

在取重载函数的地址时,会从该重载函数的名字指代的重载集中选择函数作为集合 S

  • 如果没有目标,那么就会选择所有指名的非模板函数。
  • 否则就会为目标类型的函数类型 FT 选择具有类型 F 的非模板函数,其中 F(在应用函数指针转换后)(C++17 起)等同于 FT[1]
  • 对每个指名的函数模板进行的模板实参推导生成的特化(如果存在)也会被添加到 S 中。

如果目标具有函数指针类型或到函数类型的引用类型,那么 S 只能包含非成员函数、显式对象成员函数(C++23 起)和静态成员函数。如果目标具有成员函数指针类型,那么 S 只能包含隐式对象成员函数。

  1. 也就是说,在目标类型是成员函数指针类型时会忽略函数成员的所属类。

排除函数

在组成集合 S 后会按以下顺序从其中排除函数:

  • 所有关联约束未得到满足的函数会从 S 中排除。
(C++20 起)
  • 如果 S 中还有多个函数,那么在 S 包含非模板函数时会排除 S 中的所有函数模板特化。
  • 非模板函数 func 会在 S 包含另一个比 func 更受偏序约束的非模板函数时被排除。
(C++20 起)
  • 模板函数特化 spec 会在 S 包含另一个比 spec 更特殊的模板函数特化时被排除。

排除这些函数后,S 中只能剩下正好一个函数。否则程序非良构。

示例

int f(int) { return 1; }
int f(double) { return 2; }
 
void g(int(&f1)(int), int(*f2)(double)) { f1(0); f2(0.0); }
 
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;  // 选择 int f(int)
 
    // 如 [[maybe_unused]] 一样避免“未使用变量”警告
    [](...){}(pf, rf, mpf, foo, p, t);
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告应用于出版时的行为正确行为
CWG 202C++98非类型模板实参不是重载函数语境是重载函数语境
CWG 250C++98不会从重载集中选择以未经推导生成的模板实参生成的函数模板特化也会选择
CWG 1153C++98不明确指定的函数类型是否匹配目标类型使之明确
CWG 1563C++11不明确列表初始化是否属于重载函数语境使之明确

引用

  • C++23 标准(ISO/IEC 14882:2024):
  • 12.3 Address of overloaded function [over.over]
  • C++20 标准(ISO/IEC 14882:2020):
  • 12.5 Address of overloaded function [over.over]
  • C++17 标准(ISO/IEC 14882:2017):
  • 16.4 Address of overloaded function [over.over]
  • C++14 标准(ISO/IEC 14882:2014):
  • 13.4 Address of overloaded function [over.over]
  • C++11 标准(ISO/IEC 14882:2011):
  • 13.4 Address of overloaded function [over.over]
  • C++98 标准(ISO/IEC 14882:1998):
  • 13.4 Address of overloaded function [over.over]