Namespaces
Variants

Address of an overloaded function

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

関数呼び出し式以外にも、 関数呼び出し式 において オーバーロード解決 が行われる場面を除き、オーバーロードされた関数の名前は以下の7つの文脈で現れる可能性があります:

# コンテキスト 対象
1 初期化子 オブジェクトまたは 参照 の宣言内 初期化されるオブジェクトまたは参照
2 組み込み代入式の右辺 組み込み代入の左辺
3 関数呼び出し引数として 関数パラメータ
4 ユーザー定義演算子の引数として 演算子パラメータ
5 return 関数または変換の戻り値
6 明示的キャスト または static_cast の引数 対応するキャスト
7 定数 テンプレート引数 対応するテンプレートパラメータ

各コンテキストにおいて、オーバーロードされた関数の名前はアドレス取得演算子 & が前に付き、冗長な括弧のセットで囲むことができます。

対象の型が プレースホルダ型 を含む場合、プレースホルダ型の推論が実行され、以下の説明では推論された型を対象の型として使用します。

(C++26 以降)

目次

関数の選択

オーバーロードされた関数のアドレスが取得されるとき、オーバーロード関数の名前によって参照されるオーバーロードセットから関数の集合 S が選択されます:

  • ターゲットが存在しない場合、名前が付けられたすべての非テンプレート関数が選択されます。
  • それ以外の場合、関数型 FT のターゲット型に対して、型 F の非テンプレート関数が選択されるのは、 F 関数ポインタ変換 を適用した可能性がある後) (C++17以降) FT と同一である場合です。 [1]
  • テンプレート引数推論 によって生成された特殊化(存在する場合)も S に追加されます。

ターゲットが関数ポインタ型または関数参照型の場合、 S は非メンバ関数のみを含むことができます 、明示的オブジェクトメンバ関数 (C++23以降) および静的メンバ関数。ターゲットがメンバ関数ポインタ型の場合、 S は暗黙的オブジェクトメンバ関数のみを含むことができます。

  1. 言い換えれば、ターゲット型がメンバー関数へのポインタ型である場合、関数がメンバーであるクラスは無視されます。

関数の除去

集合 S を形成した後、関数は以下の順序で除去されます:

  • 関連付けられた constraints が満たされていないすべての関数は、 S から除外されます。
(C++20以降)
  • S に複数の関数が残っている場合、 S が非テンプレート関数も含むときは、 S 内のすべての関数テンプレート特殊化が除去されます。
(C++20以降)
  • 任意の関数テンプレート特殊化 spec は、 S に関数テンプレートが spec の関数テンプレートよりも より特殊化されている 第2の関数テンプレート特殊化が含まれている場合、除去されます。

そのような除外(もしあれば)の後、選択された関数は S に正確に1つ残らなければなりません。そうでない場合、プログラムは不適格です。

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); // 第1引数には int f(int) を選択
             // 第2引数には 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++規格に対して遡及的に適用されました。

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]