オーバーロードされた関数のアドレス
オーバーロードされた関数の名前は、関数呼び出し式 (この場合はオーバーロード解決が行われます) 以外に、以下の7つの文脈で使用できます。
いずれの文脈においても、オーバーロードされた関数の名前は、アドレス取得演算子 & を前に置いても良く、冗長な括弧で囲っても構いません。
これらのすべての文脈において、ターゲット (初期化中のオブジェクトまたは参照、代入の左側、関数または演算子の仮引数、関数の戻り値の型、キャストの目的の型、またはテンプレート引数の型) によって期待される型の関数へのポインタ、関数への参照、またはメンバ関数へのポインタにマッチする型を持つ関数が、オーバーロード集合から選択されます。
関数の仮引数の型および戻り値の型はターゲットに正確に一致しなければならず、暗黙の変換は考慮されません (例えば、派生へのポインタを返す関数は、基底へのポインタを返す関数へのポインタを初期化するときは選択されません)。
関数の名前が関数テンプレートを表す場合は、まずテンプレートの実引数推定が行われ、それが成功した場合は、単一のテンプレート特殊化が生成され、それが考慮されるオーバーロード集合に追加されます。 紐付く制約が満たされないすべての関数は集合から削除されます。 (C++20以上) 集合にターゲットにマッチする関数が複数あり、そのうちの少なくともひとつが非テンプレートの場合、テンプレートの特殊化は考慮から除外されます。 非テンプレート関数のあらゆる組について、一方が他方より多く制約されている場合、そのより少なく制約されている関数は集合から除外されます。 (C++20以上) 残りのすべての候補がテンプレートの特殊化の場合、より特殊化されているものが利用可能であれば、より特殊化されていないものは削除されます。 削除の後で複数の候補が残っている場合、プログラムは ill-formed です。
例
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); // 第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) を選択します。
}
参考文献
- 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]