Address of an overloaded function
関数呼び出し式以外にも、 関数呼び出し式 において オーバーロード解決 が行われる場面を除き、オーバーロードされた関数の名前は以下の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
は暗黙的オブジェクトメンバ関数のみを含むことができます。
- ↑ 言い換えれば、ターゲット型がメンバー関数へのポインタ型である場合、関数がメンバーであるクラスは無視されます。
関数の除去
集合
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]