次のプログラムを検討してください。
#include <iostream>
template <typename T>
void f( void ( *fn )( T ) )
{
fn( 42 );
}
void g( int x )
{
std::cout << "g( " << x << " );\n";
}
int main()
{
f( g );
}
プログラムは正常にコンパイルされ、その出力は
g( 42 );
今度は、非テンプレート関数の名前を変更してみましょうg
にf
。
#include <iostream>
template <typename T>
void f( void ( *fn )( T ) )
{
fn( 42 );
}
void f( int x )
{
std::cout << "f( " << x << " );\n";
}
int main()
{
f( f );
}
現在、プログラムはgcc HEAD 10.0.0 20200およびclang HEAD 10.0.0ではコンパイルされませんが、Visual C ++ 2019では正常にコンパイルされます。
たとえば、コンパイラgccは次のメッセージセットを発行します。
prog.cc: In function 'int main()':
prog.cc:22:10: error: no matching function for call to 'f(<unresolved overloaded function type>)'
22 | f( f );
| ^
prog.cc:4:6: note: candidate: 'template<class T> void f(void (*)(T))'
4 | void f( void ( *fn )( T ) )
| ^
prog.cc:4:6: note: template argument deduction/substitution failed:
prog.cc:22:10: note: couldn't deduce template parameter 'T'
22 | f( f );
| ^
prog.cc:14:6: note: candidate: 'void f(int)'
14 | void f( int x )
| ^
prog.cc:14:13: note: no known conversion for argument 1 from '<unresolved overloaded function type>' to 'int'
14 | void f( int x )
| ~~~~^
したがって、問題が発生します。コードをコンパイルする必要がありますか。また、コードがgccおよびclangによってコンパイルされない理由は何ですか。
godboltで自分の目で確かめてください
—
Zereges
注:最初の例では、
—
Xeverous
g
(の代わりに&g
)関数テンプレートに渡すと、型の減衰が発生します(関数の左辺値参照は、関数へのポインターに減衰します:void(&)(T)
=> void(*)(T)
)。この暗黙の変換はf
、より適切な一致を持つ他のオーバーロードがないために発生します。2番目の例f
でf
は、どちらが引数なのかわからないため、実際に呼び出したい曖昧さがあります。