Considere o seguinte programa.
#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 );
}
O programa é compilado com sucesso e sua saída é
g( 42 );
Agora vamos renomear a função não modelo gpara 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 );
}
Agora, o programa não é compilado pelo gcc HEAD 10.0.0 20200 e clang HEAD 10.0.0, mas compilado com sucesso pelo Visual C ++ 2019 ..
Por exemplo, o compilador gcc emite o seguinte conjunto de mensagens.
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 )
| ~~~~^
Portanto, surge uma pergunta: o código deve ser compilado e qual é a razão pela qual o código não é compilado pelo gcc e pelo clang?
g(em vez de &g) para o modelo de função causa uma deterioração de tipo (uma referência de valor da função decai para um ponteiro para uma função: void(&)(T)=> void(*)(T)). Essa conversão implícita acontece porque não há outra fsobrecarga com uma correspondência melhor. No segundo exemplo, há uma ambiguidade que fvocê deseja chamar de fato porque ... também não sabe qual fé o argumento.