重载函数的地址
来自 cppreference.cn
除了函数调用表达式(其中发生重载决议),重载函数的名称可能出现在以下 7 个上下文中
上下文 | 目标 |
---|---|
初始化器,在对象或引用的声明中 | 正被初始化的对象或引用 |
赋值表达式的右侧 | 赋值的左侧 |
作为函数调用实参 | 函数形参 |
作为用户定义的运算符实参 | 运算符形参 |
return 语句 |
函数或转换的返回值 |
显式转型或 static_cast 实参 |
相应的转型 |
非类型模板实参 | 相应的模板形参 |
在每个上下文中,重载函数的名称可以前导地址运算符 &
,并且可以被冗余的括号集合包围。
如果目标类型包含占位符类型,则执行占位符类型推导,并且以下描述使用推导出的类型作为目标类型。 |
(自 C++26 起) |
内容 |
[编辑] 选择函数
当获取重载函数的地址时,会从重载函数名称所指的重载集中选择一个函数集合 S
- 如果没有目标,则选择所有命名的非模板函数。
- 否则,如果目标类型的函数类型
FT
与类型F
的非模板函数(可能在应用函数指针转换之后)(自 C++17 起) 相同,则选择该函数。[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++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
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]