Considérez le programme suivant.
#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 );
}
Le programme se compile avec succès et sa sortie est
g( 42 );
Renommons maintenant la fonction non modèle g
en 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 );
}
Maintenant, le programme n'est pas compilé par gcc HEAD 10.0.0 20200 et clang HEAD 10.0.0 mais compilé avec succès par Visual C ++ 2019 ..
Par exemple, le compilateur gcc émet l'ensemble de messages suivant.
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 )
| ~~~~^
Une question se pose donc: faut-il compiler le code et quelle est la raison pour laquelle le code n'est pas compilé par gcc et clang?
c++
templates
language-lawyer
c++17
template-argument-deduction
Vlad de Moscou
la source
la source
g
(au lieu de&g
) au modèle de fonction provoque une décroissance de type (une fonction lvalue référence décroît vers un pointeur vers une fonction:void(&)(T)
=>void(*)(T)
). Cette conversion implicite se produit car il n'y a pas d'autref
surcharge avec une meilleure correspondance. Dans le deuxième exemple, il y a une ambiguïté quef
vous voulez réellement appeler parce que ... il ne sait pas non plus quelf
est l'argument.Réponses:
Il me semble que gcc et clang sont corrects. Cela ne devrait pas être compilé. Le paramètre de fonction à partir duquel vous souhaitez
T
être déduit devient un contexte non déduit ici au moment où l'argument fourni est un ensemble de surcharge qui contient un modèle de fonction [temp.deduct.type] /5.5 :Ainsi,
T
ne peut être déduit et l'autre surcharge n'est pas viable en raison de l'absence de conversion; exactement ce que dit gcc…la source
Ce sont deux fonctions surchargées et la fonction non modèle doit être sélectionnée par rapport à la fonction de modèle, donc f (int x) a été sélectionné, il est donc impossible de passer une fonction comme argument dans la fonction qui doit être transmise. et ce qui suit devrait fonctionner. Merci
la source
void f<int>(void(int))
générée pour effectuer une résolution de surcharge à l'un ou l'autre niveau.