Address of an overloaded function
除了发生 函数调用表达式 的场合(此处会进行 重载解析 ),重载函数的名称还可能出现在以下7种上下文中:
| # | 上下文 | 目标 |
|---|---|---|
| 1 | 对象或 引用 声明中的 初始化器 | 被初始化的对象或引用 |
| 2 | 内置赋值表达式的右侧 | 内置赋值的左侧 |
| 3 | 作为函数调用参数 | 函数形参 |
| 4 | 作为用户自定义运算符参数 | 运算符形参 |
| 5 |
return
语句
|
函数或转换的返回值 |
| 6 |
显式转换
或
static_cast
参数
|
对应的转换目标 |
| 7 | 常量 模板参数 | 对应的模板形参 |
在每个上下文中,重载函数的名称前可以放置取址运算符
&
,并可用一对冗余的括号将其括起。
|
若目标类型包含 占位符类型 ,则执行占位符类型推导,以下描述使用推导出的类型作为目标类型。 |
(since C++26) |
目录 |
选择函数
当获取重载函数的地址时,会从重载函数名称所引用的重载集合中选出一个函数集合
S
:
- 若不存在目标,则选择所有已命名的非模板函数。
-
否则,对于目标类型的函数类型
FT,若函数类型F(可能在应用 函数指针转换 后) (C++17 起) 与FT相同,则选择该类型为F的非模板函数。 [1] -
通过
模板实参推导
为每个命名的函数模板生成的特化(若存在)也会被加入
S。
若目标为函数指针类型或函数引用类型,
S
只能包含非成员函数
、显式对象成员函数
(C++23 起)
以及静态成员函数。若目标为指向成员函数的指针类型,
S
只能包含隐式对象成员函数。
- ↑ 换句话说,当目标类型为指向成员函数的指针类型时,函数所属的类会被忽略。
函数消解
在形成集合
S
后,函数按以下顺序被消除:
|
(since C++20) |
-
如果
S中仍存在多个函数,且S同时包含非模板函数,则S中的所有函数模板特化都将被淘汰。
|
(since 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 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]