Betrachten Sie das folgende Programm.
#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 );
}
Das Programm wird erfolgreich kompiliert und seine Ausgabe ist
g( 42 );
Benennen wir nun die Nicht-Vorlagenfunktion gin um 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 );
}
Jetzt wird das Programm nicht von gcc HEAD 10.0.0 20200 und clang HEAD 10.0.0 kompiliert, sondern erfolgreich von Visual C ++ 2019 kompiliert.
Beispielsweise gibt der Compiler gcc die folgenden Nachrichten aus.
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 )
| ~~~~^
Es stellt sich also die Frage: Sollte der Code kompiliert werden und was ist der Grund, warum der Code nicht von gcc und clang kompiliert wird?
g(anstelle von &g) an die Funktionsvorlage zu einem Typabfall (eine Funktionswertreferenz zerfällt in einen Zeiger auf eine Funktion: void(&)(T)=> void(*)(T)). Diese implizite Konvertierung erfolgt, weil es keine andere fÜberlastung mit einer besseren Übereinstimmung gibt. Im zweiten Beispiel gibt es eine Mehrdeutigkeit, die fSie tatsächlich aufrufen möchten, weil ... es auch nicht weiß, welches fdas Argument ist.