602 votes

Utiliser 'class' ou 'typename' pour les paramètres des modèles ?

Duplicata possible :
Différence entre les mots-clés 'typename' et 'class' dans les modèles en C++.

Lorsqu'on définit un modèle de fonction ou un modèle de classe en C++, on peut écrire ceci :

template <class T> ...

ou on peut écrire ceci :

template <typename T> ...

Y a-t-il une bonne raison de préférer l'un à l'autre ?


J'ai accepté la réponse la plus populaire (et la plus intéressante), mais la vraie réponse semble être "Non, il n'y a pas de bonne raison de préférer l'une à l'autre."

  • Ils sont équivalents (à l'exception de ce qui est indiqué ci-dessous).
  • Certaines personnes ont des raisons de toujours utiliser typename .
  • Certaines personnes ont des raisons de toujours utiliser class .
  • Certaines personnes ont des raisons d'utiliser les deux.
  • Certaines personnes ne se soucient pas de savoir lequel elles utilisent.

Notez, cependant, qu'avant C++17, dans le cas de modèle de référence paramètres, utilisation de class au lieu de typename était nécessaire. Voir La réponse de l'utilisateur1428839 ci-dessous. (Mais ce cas particulier n'est pas une question de préférence, c'était une exigence de la langue).

6 votes

Je pense que dans ce cas, il aurait pu être justifié de rassembler toutes les réponses et d'accepter votre propre nouvelle réponse au lieu de mettre la réponse dans le texte de la question.

10 votes

Ce n'est pas vraiment un doublon. L'une demande laquelle est préférable. L'autre demande les différences.

25 votes

Je ne vois pas comment il pourrait s'agir d'une duplication d'une question posée plus d'un an plus tard.

433voto

itsmatt Points 18905

Stan Lippman a parlé de ça aquí . J'ai trouvé ça intéressant.

Résumé : Stroustrup a utilisé à l'origine class pour spécifier les types dans les modèles afin d'éviter d'introduire un nouveau mot-clé. Certains membres du comité se sont inquiétés du fait que cette surcharge du mot-clé était source de confusion. Plus tard, le comité a introduit un nouveau mot-clé typename pour résoudre une ambiguïté syntaxique, et a décidé de le laisser également être utilisé pour spécifier les types de modèles afin de réduire la confusion, mais pour une compatibilité descendante, class a gardé son sens surchargé.

7 votes

Et n'oubliez pas de lire les commentaires pour savoir s'il y a une bonne raison d'utiliser "class" plutôt que "typename".

2 votes

REVIVAL ! Je ne trouve pas cet article particulièrement clair, pour être honnête. en T::A *obj; le langage, pour autant que je sache, devrait analyser l'énoncé comme une déclaration en raison de la règle de déclaration : tout ce qui ressemble à une déclaration, même si cela ressemble de manière ambiguë à autre chose, devrait se résoudre en une déclaration[0]. Je n'ai pas non plus trouvé Bjarne Stroustrup clair à ce sujet. [0] The C++ Programming language 3e, Stroustrup, Appendix C.13.5, p. 856-858

1 votes

... de plus, Stan Lippman dit dans l'article "Ce genre de dilemme n'est pas possible avec les génériques - il n'y a aucun moyen de vérifier en toute sécurité qu'un T contient un A afin que le runtime puisse construire en toute sécurité une instance du type générique". Depuis quand les types génériques sont-ils instanciés au moment de l'exécution ? Ils sont instanciés au moment de la compilation, et pour cette raison précise, sans la fonction export nous devons définir des modèles dans les fichiers d'en-tête. Ensuite, on s'attendrait à ce que le compilateur sache tout ce qui concerne le générique instancié, y compris ce qu'il faut faire dans le cadre d'un projet. T::A c'est-à-dire un type ou une instance.

319voto

DarenW Points 7817

Selon Scott Myers, Effective C++ (3rd ed.), point 42 (qui doit, bien sûr, être la réponse ultime) - la différence est "rien".

Le conseil est d'utiliser "class" si l'on s'attend à ce que T soit toujours une classe, avec "typename" si d'autres types (int, char* ou autre) peuvent être attendus. Considérez cela comme un conseil d'utilisation.

57 votes

J'aime le concept du facteur d'indice. Je pense que je vais commencer à l'utiliser.

2 votes

"C++ Templates The Complete Guide" David Vandevoorde Nicolai M. Josuttis. 2.1.1

11 votes

Mais maintenant nous avons static_assert(std::is_class<T>::value, "T doit être une classe") ;

157voto

JorenHeit Points 577

En complément de tous les postes ci-dessus, l'utilisation de la fonction class mot-clé est (jusqu'à et y compris C++14) lorsqu'il s'agit de traiter des modèle de référence paramètres, par exemple :

template <template <typename, typename> class Container, typename Type>
class MyContainer: public Container<Type, std::allocator<Type>>
{ /*...*/ };

Dans cet exemple, typename Container aurait généré une erreur de compilation, quelque chose comme ceci :

error: expected 'class' before 'Container'

4 votes

Il semble que Clang 3.5 et Visual Studio 2015 supportent maintenant N4051 typename dans les paramètres des modèles.

2 votes

Au moins pour l'instant, c'est très important et cela rend cette réponse meilleure que les réponses acceptées et la deuxième réponse la plus élevée.

50voto

Michael Burr Points 181287

Je préfère utiliser typename parce que je ne suis pas un fan des mots-clés surchargés (bon sang - combien de significations différentes a le mot static ont pour des contextes différents ?).

40 votes

Bien sûr, typename est également surchargé.....

8 votes

C'est vrai, mais cela semble être moins surchargé en termes de confusion - les autres utilisations de typename sont déroutantes, non pas à cause de la surcharge, mais parce que les situations où elle est requise sont assez déroutantes. D'autres surcharges de mots-clés ( class o static ) semblent participer activement à la confusion.

5 votes

Je suis d'accord avec l'utilisation de typename ici -- l'utilisation de classe semble surutiliser ce mot-clé, en particulier dans les cas de template<class X> class Y { ...

9voto

Aaron Points 2456

En réponse à Mike B Je préfère utiliser 'class' car, dans un modèle, 'typename' a une signification surchargée, mais pas 'class'. Prenons l'exemple de ce type d'entier vérifié :

template <class IntegerType>
class smart_integer {
public: 
    typedef integer_traits<Integer> traits;
    IntegerType operator+=(IntegerType value){
        typedef typename traits::larger_integer_t larger_t;
        larger_t interm = larger_t(myValue) + larger_t(value); 
        if(interm > traits::max() || interm < traits::min())
            throw overflow();
        myValue = IntegerType(interm);
    }
}

larger_integer_t est un nom dépendant, il doit donc être précédé de 'typename' pour que l'analyseur syntaxique puisse reconnaître que larger_integer_t est un type. classe par contre, n'a pas une telle surcharge de sens.

Ça... ou je suis juste paresseux dans l'âme. Je tape 'class' bien plus souvent que 'typename', et je trouve donc cela bien plus facile à taper. Ou alors, c'est le signe que j'écris trop de code OO.

9 votes

Je ne considère pas cela comme une surcharge. Dans les deux cas, typename fait la même chose : signifier qu'il est suivi d'un type au lieu d'une variable.

4 votes

Mais "typedef" est toujours suivi d'un type, alors pourquoi "typename" est-il nécessaire ici ? Je peux comprendre qu'il soit nécessaire dans quelque chose comme typename qwert::yuiop * asdfg; si nécessaire pour indiquer à l'analyseur syntaxique qu'il s'agit d'une déclaration de pointeur et non d'une expression de multiplication. Mais dans un typedef, il n'y a pas de telle ambiguïté.

1 votes

Vous avez peut-être raison, je ne suis pas sûr que ce soit strictement nécessaire dans mon exemple. Votre exemple est supérieur, car "qwerty::yuiop * asdfg ;" pourrait soit déclarer une variable pointeur, soit invoquer l'opérateur de multiplication.

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