2009-10-21 8 views
4

En fait, j'ai un problème avec la compilation d'une bibliothèque avec un compilateur intel.Problème de modèles ('typename' en tant que paramètre de fonction non template)

Cette même bibliothèque a été compilée correctement avec g ++.

Un problème est dû aux modèles. Ce que je voudrais comprendre est la déclaration de **typename** ne pas paramètre de fonction modèle et la déclaration variable dans le corps de la fonction

exemple:

void func(typename sometype){.. 
... 
typename some_other_type; 
.. 
} 

Compilation ce genre de produits de code erreurs suivantes (intel), (gcc ne prétend pas): J'ai des erreurs suivantes

../../../libs/log/src/attribute_set.cpp(415): error: no operator "!=" matches these operands 
      operand types are: boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> != boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> 
     while (begin != end) 
       ^
      detected during instantiation of "void boost::log_st::basic_attribute_set<CharT>::erase(boost::log_st::basic_attribute_set<CharT>::iter<'\000'>, boost::log_st::basic_attribute_set<CharT>::iter<'\000'>) [with CharT=wchar_t]" at line 438 

../../../boost/log/attributes/attribute_set.hpp(115): error: no operator "!=" matches these operands 
      operand types are: boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> != boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> 
       if (it != m_pContainer->end()) 

Ce que je voudrais comprendre est l'utilisation de la typename à l'intérieur du BOD y de fonctions, déclarations de paramètres.

ex .:

template< typename CharT > 
struct basic_attribute_values_view<CharT>::implementation 
{ 

public: 
.. 
.. 
void adopt_nodes(**typename attribu**te_set_type::const_iterator& it, **typename attribut**e_set_type::const_iterator end) 
    { 
     for (; it != end; ++it) 
      push_back(it->first, it->second.get()); 
    } 

dans un fichier différent j'ai:

template< typename CharT > 
class basic_attribute_set 
{ 
    friend class basic_attribute_values_view<CharT>; 

    //! Self type 
    typedef basic_attribute_set<CharT> this_type; 

public: 
    //! Character type 
    typedef CharT char_type; 
    //! String type 
    typedef std::basic_string<char_type> string_type; 
    //! Key type 
    typedef basic_slim_string<char_type> key_type; 
    //! Mapped attribute type 
    typedef shared_ptr<attribute> mapped_type; 

    //! Value type 
    typedef std::pair< const key_type, mapped_type > value_type; 
    //! Allocator type 
    typedef std::allocator<value_type> allocator_type; 
    //! Reference type 
    **typedef typename allocator_type::reference reference;** 
+0

Ce serait plus facile ... si nous avions le code qui a généré l'erreur du compilateur (avec les lignes incriminées indiquées). Notez que l'utilisation de '**' pour la syntaxe ne fonctionne pas dans les blocs de code. –

+0

Toutes les actions iterator! = Dans mon exemple produisent des erreurs simmilar, donc ce serait la ligne (it! = End;) dans mon premier exemple de code. – bua

Répondre

12

Vous devez utiliser typename pour soi appelé "types dépendants". Ce sont des types qui dépendent d'un argument template et ne sont pas connus avant l'instanciation du template. Il est probablement mieux expliqué par un exemple:

struct some_foo { 
    typedef int bar; 
}; 

template< typename Foo > 
struct baz { 
    typedef Foo::bar barbar; // wrong, shouldn't compile 

    barbar f(); // would be fine if barbar were a type 

    // more stuff... 
}; 

Ce typedef la définition barbar est celui qui a besoin d'un typename pour que le compilateur pour être en mesure de vérifier le modèle pour les erreurs de syntaxe flagrante avant il est instancié avec un béton type. La raison en est que, lorsque le compilateur voit le modèle pour la première fois (lorsqu'il n'est pas encore instancié avec des paramètres de modèle concrets), le compilateur ne sait pas si Foo::bar est un type.Pour tout ce qu'il sait, je pourrais l'intention baz à instancier avec des types comme celui-ci

struct some_other_foo { 
    static int bar; 
}; 

auquel cas Foo::bar se réfère à un objet , pas un type, et la définition de baz::bar serait un non-sens syntaxique. Sans savoir si Foo::bar fait référence à un type, le compilateur n'a aucune chance de vérifier quoi que ce soit au sein de baz qui utilise directement ou indirectement barbar même pour les fautes les plus stupides jusqu'à ce que baz soit instancié. Utilisation de la typename appropriée, baz ressemble à ceci:

template< typename Foo > 
struct baz { 
    typedef typename Foo::bar barbar; 

    barbar f(); 

    // more stuff... 
}; 

Maintenant, le compilateur au moins sait que Foo::bar est censé être le nom d'un type qui fait barbar un nom de type, aussi. Donc, la déclaration de f() est syntactique OK, aussi.

Par ailleurs, il y a un problème similaire avec des modèles au lieu des types:

template< typename Foo > 
struct baz { 
    Foo::bar<Foo> create_wrgl(); // wrong, shouldn't compile 
}; 

Lorsque le compilateur « voit » Foo::bar il ne sait pas ce qu'elle est, si bar<Foo pourrait tout aussi bien être une comparaison , laissant le compilateur confus au sujet de la fin >. Ici, vous devez aussi donner au compilateur un soupçon que Foo::bar est censé être le nom d'un modèle:

template< typename Foo > 
struct baz { 
    Foo::template bar<Foo> create_wrgl(); 
}; 

Attention: Notamment Visual C++ ne reste implémente pas une bonne recherche en deux phases (en substance: il ne vérifie pas vraiment les templates tant qu'ils ne sont pas instanciés). Par conséquent, il accepte souvent un code erroné qui manque un typename ou un template.

+2

+1 pour la mention de recherche en deux phases. D'où le conseil: si possible, essayez de compiler votre code avec au moins 2 compilateurs différents. – Francesco

3

Le point du mot-clé typename est de dire au compilateur que quelque chose est un typename, dans des situations où il n'est pas évident. Prenez cet exemple:

template<typename T> 
void f() 
{ 
    T::foo * x; 
} 

est-T::foo un type, ce qui signifie que nous proclamons un pointeur, ou est T::foo une variable statique, et nous faisons une multiplication?

Puisque le compilateur n'a aucune idée de ce que T pourrait être au moment où il lit le modèle, il n'a aucune idée de ce qui est correct dans les deux cas.

La norme dicte que le compilateur devrait assumer ce dernier cas, et seulement interpréter T::foo comme typename si elle est précédée par le mot-clé typename, comme ceci:

template<typename T> 
void f() 
{ 
    typename T::foo* x; //Definitely a pointer. 
} 
0

Sur votre code:

void func(typename sometype) 
{ 
    .....typename some_other_type; 
    .. 
} 

Si le code ci-dessus ne fait pas partie d'un modèle, il ne peut pas être compilé en utilisant g ++, à moins que l'ancienne version de g ++.

Comme mon expérience, FC9 ou GNU C/++ version 4.2x sera le signaler comme une erreur, il va se plaindre:

typename only can be used in template code 

tout FC8 ou GNU C/++ 4.1x ne peut.

S'il vous plaît voir

http://code.google.com/p/effocore/source/browse/trunk/devel/effo/codebase/addons/inl/include/ringed_inl.h 
and 
http://code.google.com/p/effocore/source/browse/trunk/devel/effo/codebase/addons/inl/include/cont_inl.h 

pour plus de modèles et des exemples typename.

Questions connexes