50 votes

Pourquoi dois-je utiliser typedef typename dans g++ mais pas dans VS ?

Cela faisait un moment que GCC ne m'avait pas attrapé avec celui-ci, mais c'est arrivé aujourd'hui. Mais je n'ai jamais compris pourquoi GCC exige typedef typename dans les templates, alors que VS et ICC, je suppose, ne le font pas. Est-ce que le typedef typename est un "bug" ou une norme trop stricte, ou quelque chose qui est laissé à la discrétion des auteurs de compilateurs ?

Pour ceux qui ne savent pas ce que je veux dire, voici un échantillon :

template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
    std::map<KEY,VALUE>::const_iterator iter = container.find(key);
    return iter!=container.end();
}

Le code ci-dessus compile dans VS (et probablement dans ICC), mais échoue dans GCC parce qu'il le veut comme ceci :

template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
    typedef typename std::map<KEY,VALUE>::const_iterator iterator; //typedef typename
    iterator = container.find(key);
    return iter!=container.end();
}

Note : Il ne s'agit pas d'une fonction réelle que j'utilise, mais juste d'une fonction idiote qui illustre le problème.

56voto

Le typename est requis par la norme. La compilation des templates nécessite une vérification en deux étapes. Lors de la première passe, le compilateur doit vérifier la syntaxe du modèle sans fournir les substitutions de type. Dans cette étape, std::map::iterator est supposé être une valeur. S'il désigne un type, le mot-clé typename est requis.

Pourquoi cela est-il nécessaire ? Avant de substituer les types KEY et VALUE réels, le compilateur ne peut pas garantir que le modèle n'est pas spécialisé et que la spécialisation ne redéfinit pas les types KEY et VALUE. itérateur mot-clé comme quelque chose d'autre.

Vous pouvez le vérifier avec ce code :

class X {};
template <typename T>
struct Test
{
   typedef T value;
};
template <>
struct Test<X>
{
   static int value;
};
int Test<X>::value = 0;
template <typename T>
void f( T const & )
{
   Test<T>::value; // during first pass, Test<T>::value is interpreted as a value
}
int main()
{
  f( 5 );  // compilation error
  X x; f( x ); // compiles fine f: Test<T>::value is an integer
}

Le dernier appel échoue avec une erreur indiquant que lors de la première étape de compilation du modèle de f() Test::value a été interprété comme une valeur mais que l'instanciation du modèle Test<> avec le type X donne un type.

32voto

Magnus Hoff Points 12052

Eh bien, GCC n'a pas vraiment exiger le site typedef -- typename est suffisant. Cela fonctionne :

#include <iostream>
#include <map>

template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
    typename std::map<KEY,VALUE>::const_iterator iter = container.find(key);
    return iter!=container.end();
}

int main() {
    std::map<int, int> m;
    m[5] = 10;
    std::cout << find(m, 5) << std::endl;
    std::cout << find(m, 6) << std::endl;
    return 0;
}

C'est un exemple de problème d'analyse syntaxique sensible au contexte. La signification de la ligne en question n'est pas évidente à partir de la syntaxe de cette fonction seulement -- vous devez savoir si std::map<KEY,VALUE>::const_iterator est un type ou non.

Maintenant, je n'arrive pas à penser à un exemple de ce que... ::const_iterator pourrait être sauf un type, ce ne serait pas non plus une erreur. Donc, je suppose que le compilateur peut découvrir que c'est a pour être un type, mais cela pourrait être difficile pour le pauvre compilateur (écrivains).

La norme exige l'utilisation de typename ici, conformément à la litb par la section 14.6/3 de la norme.

4voto

dirkgently Points 56879

Il semble que VS/ICC fournisse le typename mot-clé partout où il pense il est nécessaire. Notez que c'est une mauvaise chose (TM) -- laisser le compilateur décider de ce qui est nécessaire. vous veulent. Cela complique encore la question en inculquant la mauvaise habitude de sauter la typename lorsque cela est nécessaire et c'est un cauchemar en matière de portabilité. Ce n'est absolument pas le comportement standard. Essayez en mode standard strict ou Comeau.

3voto

Joe Gauterin Points 9526

Il s'agit d'un bogue du compilateur Microsoft C++. Dans votre exemple, std::map::iterator pourrait ne pas être un type (vous auriez pu spécialiser std::map sur KEY,VALUE de sorte que std::map::iterator soit une variable, par exemple).

GCC vous oblige à écrire un code correct (même si ce que vous vouliez dire était évident), alors que le compilateur de Microsoft devine correctement ce que vous vouliez dire (même si le code que vous avez écrit était incorrect).

2voto

Yttrill Points 2461

Il convient de noter que la question du classement par valeur/type n'est pas le problème fondamental. Le problème principal est analyse syntaxique de . Considérons

template<class T>
void f() { (T::x)(1); }

Il n'y a aucun moyen de savoir s'il s'agit d'un cast ou d'un appel de fonction, sauf si le mot-clé typename est obligatoire. Dans ce cas, le code ci-dessus contient un appel de fonction. En général, le choix ne peut pas être retardé sans renoncer à l'analyse syntaxique, comme le montre le fragment suivant

(a)(b)(c)

Au cas où vous ne vous en souviendriez pas, le cast a une priorité plus élevée que l'appel de fonction en C, une des raisons pour lesquelles Bjarne voulait des cast de style fonction. Il n'est donc pas possible de dire si ce qui précède signifie

(a)(b)  (c)   // a is a typename

ou

(a) (b)(c)    // a is not a typename , b is

ou

(a)(b) (c)    // neither a nor b is a typename

où j'ai inséré un espace pour indiquer le regroupement.

Notez également que le mot clé "templatename" est nécessaire pour la même raison que "typename", vous ne pouvez pas analyser les choses sans connaître leur type en C/C++.

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