除了函数调用表达式之外,重载函数的名字还可以出现在下列 7 种发生重载决议的语境中:
2) 赋值运算符的右侧
3) 作为函数调用的实参
4) 作为用户定义运算符的实参
5) return 语句
6) 显式转型或 static_cast 的实参
7) 非类型模板实参
在每个语境中,重载函数的名称可以前附取址运算符 &
并且可以被一组冗余的括号所环绕。
在所有这些语境中,从重载集中选择的函数,是其类型与目标所期待的函数指针、函数引用或成员函数指针类型相匹配的函数,目标分别为:被初始化的对象或引用,赋值的左侧,函数或运算符的形参,函数的返回类型,转型的目标类型,以及模板形参的类型。
函数的形参类型和返回类型必须与目标严格匹配,不考虑隐式转换(例如,在初始化指向返回基类指针的函数的指针时,不会选择返回派生类指针的函数)。
若函数名指名某个函数模板,则首先进行模板实参推导,而若其成功,则将生成一个单独的模板特化并添加到所要考虑的重载集合中。从集合中丢弃所有不满足其关联制约的函数。 (C++20 起)若集合中有多于一个函数与目标匹配,且至少一个函数是非模板,则从考虑中去除模板特化。对于任何一对非模板函数,其中之一比另一个更受制约,则从集合中丢弃受较少制约的函数。 (C++20 起)若所有剩余候选者都是模板特化,则当存在更特殊的模板特化时,移除较不特殊者。若在各项移除之后仍留有多于一个候选者,则程序非良构。
示例
运行此代码
- int f(int) { return 1; }
- int f(double) { return 2; }
- void g( int(&f1)(int), int(*f2)(double) ) {}
- 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; // selects int f(int)
- }
引用
- C++11 standard (ISO/IEC 14882:2011):
- 13.4 Address of overloaded function [over.over]
- C++98 standard (ISO/IEC 14882:1998):
- 13.4 Address of overloaded function [over.over]
当前内容版权归 cppreference 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 cppreference .