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 g
a 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 otraf
sobrecarga con una mejor coincidencia. En el segundo ejemplo, hay una ambigüedad a la quef
quieres llamar porque ... tampoco sabe cuálf
es el argumento.Respuestas:
Me parece que gcc y clang son correctos. Esto no debe compilarse. El parámetro de función del que desea
T
deducirse 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,
T
no 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.