Considera il seguente programma.
#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 );
}
Il programma viene compilato correttamente e il suo output è
g( 42 );
Ora rinominiamo la funzione non modello gin 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 );
}
Ora il programma non è compilato da gcc HEAD 10.0.0 20200 e clang HEAD 10.0.0 ma compilato con successo da Visual C ++ 2019 ..
Ad esempio il compilatore gcc emette il seguente set di messaggi.
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 )
| ~~~~^
Quindi sorge una domanda: il codice dovrebbe essere compilato e qual è la ragione per cui il codice non è compilato da gcc e clang?
g(anziché &g) al modello di funzione provoca un decadimento del tipo (un riferimento al valore di una funzione decade in un puntatore a una funzione: void(&)(T)=> void(*)(T)). Questa conversione implicita avviene perché non c'è altro fsovraccarico con una corrispondenza migliore. Nel secondo esempio, c'è un'ambiguità che fin realtà vuoi chiamare perché ... non sa nemmeno quale fsia l'argomento.