J'ai essayé de comprendre comment C++ sélectionne les modèles. Notamment, considérez l'exemple de code suivant :
template
class Curious
{
public:
template ::value, int>::type = 33>
void test1() {}
template ::value, int>::type = 33>
void test1() {}
template ::value>::type>
void test2() {}
template ::value>::type>
void test2() {}
template ::value>::type * = nullptr>
void test3() {}
template ::value>::type * = nullptr>
void test3() {}
// works
template
typename std::enable_if::value, T>::type test4() {}
template
typename std::enable_if::value, T>::type test4() {}
// also works
template ::value, T>::type * = nullptr>
void test5() {}
template ::value, T>::type * = nullptr>
void test5() {}
}; // Curious
Les deux premières fonctions (test1) fonctionnent bien (pourquoi ?) :
Curious curious;
curious.test1();
curious.test1();
Tandis que les autres provoquent des erreurs de compilation. Concernant la fonction test2, le compilateur affirme que je tente de créer un doublon :
error C2535: 'void Curious::test2(void)': member function already defined or declared
Ici, la documentation indique :
Une erreur courante est de déclarer deux modèles de fonction qui ne diffèrent que par leurs arguments de modèle par défaut. Ceci est illégal car les arguments de modèle par défaut ne font pas partie de la signature du modèle de fonction, et déclarer deux modèles de fonction différents avec la même signature est illégal.
Il semble donc que ce soit le cas. Cependant, je ne vois pas beaucoup de différence par rapport aux deux premières fonctions, qui ont également l'argument de modèle par défaut. Ainsi, nous avons un type par défaut (test2 - ne fonctionne pas) contre une valeur par défaut (test1 - fonctionne). Y a-t-il une règle à ce sujet ?
Dans le cas de test3 :
error C2039: 'type': is not a member of 'std::enable\_if'Comme dans le premier cas, cette fois-ci, la fonction membre du modèle a un paramètre par défaut non typé, mais cela dépend du paramètre du modèle de classe. Maintenant, SFINAE ne saute pas le mauvais choix (je ne suis pas sûr pourquoi).
Dans le quatrième cas, SFINAE résout le modèle par le type de retour. Mais est-ce que ces fonctions test4 ont une signature identique ? Car elles ne diffèrent que par le type de retour.
D'après ce que je comprends, dans le cinquième cas, l'ajout d'un paramètre supplémentaire rend la signature de test5 dépendante du paramètre du modèle de fonction, donc SFINAE entre en jeu et la résolution fonctionne.
Je suis assez confus sur la façon dont C++ gère ces modèles. Est-ce que quelqu'un pourrait avoir la gentillesse de clarifier ces points ?