web-dev-qa-db-ja.com

C ++が代入演算子の右側のテンプレート引数を左側から推測できるのはなぜですか?

template <typename T>
void func(T&){
}

int main(){
    void (*p)(int&) = func;//or &func
    return 0;
}

なぜこのコードが(g ++で)コンパイルされるのだろうか。テンプレート関数の引数はpの型から推測されているようです。これは標準的な動作ですか?

編集:私は可能な説明を思いついた。その割り当てには署名があります。

void(*&)(int&)operator=(void(*)(int&));

したがって、funcは、実際には、pの型から直接ではなく、operator =の入力引数の型から推定されます。あれは正しいですか?

32
lowsfer

これは標準的な動作ですか?

はい、そうです。テンプレート引数の推定は、関数テンプレートのアドレスを取得するときにも発生します(関数ポインターの割り当てや初期化の場合など)。 [temp.deduct.funcaddr]/1 で明示的に許可されています:

テンプレート引数は、オーバーロードされた関数のアドレスを取得するときに指定された型から推測できます。関数テンプレートの関数型と指定された型がPとAの型として使用され、[temp.deduct.type]で説明されているように推定が行われます。

関数ポインタ型は引数を提供します(上記の段落のA)。

したがって、funcは、実際には、pの型から直接ではなく、operator =の入力引数の型から推定されます。あれは正しいですか?

あんまり。一つには、それは割り当てではなく、あなたがしているのは初期化です。また、オーバーロードされたoperator=関数を使用していた場合でも、代入演算子の引数を初期化するために推論が必要になります。これにより、正方形に戻ります。

29
StoryTeller