6 votes

Sélection de modèle de fonction membre et SFINAE

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 ?

8voto

Jarod42 Points 15729
  • Avec la valeur par défaut supprimée, pour test1, vous avez :

    template ::value, int>::type>
    void test1();
    
    template ::value, int>::type>
    void test1();

    Qui ont des signatures clairement différentes.

  • Pour test2 :

    template  void test2();
    
    template  void test2();

    Qui ont des signatures clairement identiques.

  • Pour test3, la SFINAE ne s'applique pas car vous avez une erreur bloquante puisque R est fixé dans la classe et votre enable_if ne dépend pas du paramètre du template de la fonction.

  • Pour test4, il y a une exception concernant la signature des fonctions de modèle car les surcharges peuvent différer uniquement par le type de retour, donc

    int foo();
    char foo(); // Illégal.

    mais

    template  int foo();
    template  char foo(); // légal, même s'il n'est pas trivial à appeler

    De plus, std::enable_if::value, T>::type dépend du paramètre de modèle T donc c'est bon.

  • Pour test5, le deuxième paramètre de modèle dépend du premier paramètre de modèle T, donc c'est bon aussi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X