Considere el siguiente 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 );
}
El programa se compila correctamente y su salida es
g( 42 );
Ahora cambiemos el nombre de la función sin plantilla ga 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 );
}
Ahora el programa no está compilado por gcc HEAD 10.0.0 20200 y clang HEAD 10.0.0 sino compilado con éxito por Visual C ++ 2019 ..
Por ejemplo, el compilador gcc emite el siguiente conjunto de mensajes.
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 )
| ~~~~^
Entonces surge una pregunta: ¿debe compilarse el código y cuál es la razón por la cual el código no está compilado por gcc y clang?
c++
templates
language-lawyer
c++17
template-argument-deduction
Vlad de Moscú
fuente
fuente

g(en lugar de&g) a la plantilla de función provoca una caída de tipo (una referencia de valor de función l decae a un puntero a una función:void(&)(T)=>void(*)(T)). Esta conversión implícita ocurre porque no hay otrafsobrecarga con una mejor coincidencia. En el segundo ejemplo, hay una ambigüedad a la quefquieres llamar porque ... tampoco sabe cuálfes el argumento.Respuestas:
Me parece que gcc y clang son correctos. Esto no debe compilarse. El parámetro de función del que desea
Tdeducirse se convierte en un contexto no deducido aquí en el momento en que el argumento suministrado es un conjunto de sobrecarga que contiene una plantilla de función [temp.deduct.type] /5.5 :Por lo tanto,
Tno se puede deducir y la otra sobrecarga no es viable debido a que no hay conversión; exactamente lo que dice gcc ...fuente
Estas son dos funciones sobrecargadas y la función sin plantilla se debe seleccionar en comparación con la función con plantilla, por lo que se seleccionó f (int x), por lo tanto, pasar una función como argumento en la función que int debe pasar es imposible. y lo siguiente debería funcionar. Gracias
fuente
void f<int>(void(int))genera una especialización para hacer una resolución de sobrecarga en cualquier nivel.