Domanda

In realtà ho un problema con la compilazione di alcune librerie con il compilatore Intel.

Questa stessa libreria è stata compilata correttamente con g ++.

Il problema è causato dai modelli. Quello che vorrei capire è la dichiarazione di **typename** come non parametro della funzione del modello e dichiarazione delle variabili all'interno del corpo della funzione

Esempio:

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

La compilazione di questo tipo di codice produce i seguenti errori (intel), (gcc non rivendica): Ho i seguenti errori

../../../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())

Quello che vorrei capire è l'uso del nome tipografico all'interno del corpo delle funzioni, dichiarazioni dei parametri.

es:.

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());
    }

in un altro file ho:

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;**
È stato utile?

Soluzione

Devi usare typename per i cosiddetti " tipi dipendenti " ;. Questi sono tipi che dipendono da un argomento del modello e non sono noti fino a quando il modello non viene istanziato. Probabilmente è meglio spiegato usando un esempio:

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...
};

Che typedef la definizione di barbar sia uno che richiede un Foo::bar affinché il compilatore sia in grado di controllare il modello per evidenti errori sintattici prima , viene istanziato con un tipo concreto . Il motivo è che, quando il compilatore vede il modello per la prima volta (quando non è ancora istanziato con parametri di modello concreti), il compilatore non sa se baz è un tipo. Per quanto ne so, potrei voler baz::bar essere istanziato con tipi come questo

struct some_other_foo {
  static int bar;
};

nel qual caso f() farebbe riferimento a un oggetto , non a un tipo, e la definizione di bar<Foo sarebbe una sciocchezza sintattica. Senza sapere se > si riferisce a un tipo, il compilatore non ha alcuna possibilità di controllare nulla all'interno di template che utilizza direttamente o indirettamente <=> anche per i refusi più stupidi fino a quando <=> non viene istanziato. Utilizzando il <=> corretto, <=> è simile al seguente:

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

  barbar f();

  // more stuff...
};

Ora almeno il compilatore sa che <=> dovrebbe essere il nome di un tipo, il che rende anche <=> un nome di tipo. Quindi anche la dichiarazione di <=> è sintattica.

A proposito, c'è un problema simile con i template invece dei tipi:

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

Quando il compilatore " vede " <=> non sa di cosa si tratta, quindi <=> potrebbe anche essere un confronto, lasciando il compilatore confuso sul trailing <=>. Anche qui, devi dare al compilatore un suggerimento che <=> dovrebbe essere il nome di un modello:

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

Attenzione: in particolare Visual C ++ non implementa ancora una corretta ricerca in due fasi (in sostanza: non controlla realmente i modelli fino a quando non vengono istanziati). Pertanto accetta spesso un codice errato che manca un <=> o un <=>.

Altri suggerimenti

Il punto della parola chiave typename è dire al compilatore che qualcosa è un nome tipografico, in situazioni in cui non è ovvio. Prendi questo esempio:

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

T::foo è un tipo, nel senso che stiamo dichiarando un puntatore, oppure <=> è una variabile statica e stiamo facendo una moltiplicazione?

Poiché il compilatore non ha idea di cosa potrebbe essere T nel momento in cui legge il modello, non ha idea di quale dei due casi sia corretto.

Lo standard impone che il compilatore debba assumere l'ultimo caso e interpretare <=> come un nome di tipo solo se è preceduto dalla parola chiave <=>, in questo modo:

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

Sul tuo codice:

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

Se il codice sopra riportato non fa parte di un modello, non può essere compilato usando g ++, a meno che la vecchia versione di g ++.

Come il mio esperto, FC9 o GNU C / ++ versione 4.2x lo segnalerà come un errore, si lamenterà:

typename only can be used in template code

mentre FC8 o GNU C / ++ 4.1x non possono.

Vedi

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

per altri esempi di modelli e nomi tipografici.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top