命名空间
变体
操作

重载函数的地址

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (直到 C++17* 已弃用)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

除了函数调用表达式(其中发生重载决议),重载函数的名称可能出现在以下 7 个上下文中

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

在每个上下文中,重载函数的名称可以前导地址运算符 &,并且可以被冗余的括号集合包围。

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

(自 C++26 起)

内容

[编辑] 选择函数

当获取重载函数的地址时,会从重载函数名称所指的重载集中选择一个函数集合 S

  • 如果没有目标,则选择所有命名的非模板函数。
  • 否则,如果目标类型的函数类型 FT 与类型 F 的非模板函数(可能在应用函数指针转换之后)(自 C++17 起) 相同,则选择该函数。[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++ 标准。

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]