problema dei modelli ('typename' come non parametro della funzione template)
-
05-07-2019 - |
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;**
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.