重载函数地址
来自 cppreference.cn
除了发生重载决议的函数调用表达式之外,重载函数的名称可以出现在以下 7 种语境中
语境 | 目标 |
---|---|
对象或引用声明中的初始化器 | 被初始化的对象或引用 |
赋值表达式的右侧 | 赋值表达式的左侧 |
作为函数调用参数 | 函数参数 |
作为用户定义运算符参数 | 运算符参数 |
return 语句 |
函数或转换的返回值 |
显式转换或 static_cast 参数 |
相应的转换 |
非类型模板参数 | 相应的模板参数 |
在每个语境中,重载函数的名称前面可以带有取址运算符 &
,并且可以被一对多余的括号括起来。
如果目标类型包含占位符类型,则执行占位符类型推导,以下描述使用推导类型作为目标类型。 |
(C++26 起) |
目录 |
[编辑] 选择函数
当取一个重载函数的地址时,会从由重载函数名称引用的重载集中选择一个函数集合 S
- 如果没有目标,则选择所有非模板函数。
- 否则,如果类型为
F
的非模板函数(在可能应用函数指针转换后)(C++17 起)与目标类型的函数类型FT
相同,则选择该函数。[1] - 通过对每个命名的函数模板进行模板参数推导所生成的特化(如果有)也被添加到
S
中。
如果目标是函数指针类型或函数引用类型,则 S
只能包含非成员函数、显式对象成员函数(C++23 起)和静态成员函数。如果目标是指向成员函数指针类型,则 S
只能包含隐式对象成员函数。
- ↑ 换句话说,如果目标类型是指向成员函数指针类型,则忽略该函数所属的类。
[编辑] 消除函数
形成集合 S
后,按以下顺序消除函数
|
(C++20 起) |
- 如果
S
中剩下多个函数,则如果S
也包含非模板函数,则消除S
中的所有函数模板特化。
|
(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]