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 g
in 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?
c++
templates
language-lawyer
c++17
template-argument-deduction
Vlad aus Moskau
quelle
quelle
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 anderef
Überlastung mit einer besseren Übereinstimmung gibt. Im zweiten Beispiel gibt es eine Mehrdeutigkeit, dief
Sie tatsächlich aufrufen möchten, weil ... es auch nicht weiß, welchesf
das Argument ist.Antworten:
Es scheint mir, dass gcc und clang richtig sind. Dies sollte nicht kompiliert werden. Der Funktionsparameter, aus dem Sie
T
abgeleitet werden möchten, wird hier zu einem nicht abgeleiteten Kontext, sobald das angegebene Argument eine Überladungsmenge ist, die eine Funktionsvorlage [temp.deduct.type] /5.5 enthält :Somit
T
kann nicht abgeleitet werden , und die andere Überlastung ist nicht lebensfähig aufgrund keine Umwandlung ist; genau das, was gcc sagt ...quelle
Dies sind zwei überladene Funktionen, und die Nicht-Vorlagenfunktion sollte im Vergleich zur Vorlagenfunktion ausgewählt werden. Daher wurde f (int x) ausgewählt, sodass die Übergabe einer Funktion als Argument in der Funktion, die int übergeben werden muss, unmöglich ist. und das unten sollte funktionieren. Vielen Dank
quelle
void f<int>(void(int))
generiert, um eine Überlastungsauflösung auf beiden Ebenen durchzuführen.