命名空间
变体
操作

重载函数地址

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
 
 

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

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

在每个语境中,重载函数的名称前面可以带有取址运算符 &,并且可以被一对多余的括号括起来。

如果目标类型包含占位符类型,则执行占位符类型推导,以下描述使用推导类型作为目标类型。

(C++26 起)

目录

[编辑] 选择函数

当取一个重载函数的地址时,会从由重载函数名称引用的重载集中选择一个函数集合 S

  • 如果没有目标,则选择所有非模板函数。
  • 否则,如果类型为 F 的非模板函数(在可能应用函数指针转换后)(C++17 起)与目标类型的函数类型 FT 相同,则选择该函数。[1]
  • 通过对每个命名的函数模板进行模板参数推导所生成的特化(如果有)也被添加到 S 中。

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

  1. 换句话说,如果目标类型是指向成员函数指针类型,则忽略该函数所属的类。

[编辑] 消除函数

形成集合 S 后,按以下顺序消除函数

  • 所有具有不满足的关联约束的函数都从 S 中消除。
(C++20 起)
  • 如果 S 中剩下多个函数,则如果 S 也包含非模板函数,则消除 S 中的所有函数模板特化。
  • 如果 S 包含第二个非模板函数,其偏序约束比给定非模板函数 func 更强,则消除 func
(C++20 起)
  • 如果 S 包含第二个函数模板特化,其函数模板比给定函数模板特化 spec 的函数模板更特化,则消除 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. initialization
    int (*pf)(double) = f; // selects int f(double)
    int (&rf)(int) = f; // selects int f(int)
    int (Foo::*mpf)(int) = &Foo::mf; // selects int mf(int)
 
    // 2. assignment
    pf = nullptr;
    pf = &f; // selects int f(double)
 
    // 3. function argument
    g(f, f); // selects int f(int) for the 1st argument
             // and int f(double) for the second
 
    // 4. user-defined operator
    Emp{} << f; //selects int f(double)
 
    // 5. return value
    auto foo = []() -> int (*)(int)
    {
        return f; // selects int f(int)
    };
 
    // 6. cast
    auto p = static_cast<int(*)(int)>(f); // selects int f(int)
 
    // 7. template argument
    Templ<f> t;  // selects int f(int)
 
    // prevent “unused variable” warnings as if by [[maybe_unused]]
    [](...){}(pf, rf, mpf, foo, p, t);
}

[编辑] 缺陷报告

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

缺陷报告 应用于 发布时的行为 正确的行为
CWG 202 C++98 非类型模板参数不是
取重载函数地址的语境
它是
CWG 250 C++98 使用非推导模板参数生成的函数模板特化
未从重载集中选择
也选择
CWG 1153 C++98 不清楚给定函数类型是否与目标类型匹配 已明确
CWG 1563 C++11 不清楚列表初始化是否是一个语境
取重载函数地址的语境
已明确

[编辑] 参考资料

  • C++23 标准 (ISO/IEC 14882:2024)
  • 12.3 重载函数地址 [over.over]
  • C++20 标准 (ISO/IEC 14882:2020)
  • 12.5 重载函数地址 [over.over]
  • C++17 标准 (ISO/IEC 14882:2017)
  • 16.4 重载函数地址 [over.over]
  • C++14 标准 (ISO/IEC 14882:2014)
  • 13.4 重载函数地址 [over.over]
  • C++11 标准 (ISO/IEC 14882:2011)
  • 13.4 重载函数地址 [over.over]
  • C++98 标准 (ISO/IEC 14882:1998)
  • 13.4 重载函数地址 [over.over]