Domanda

So che i compilatori hanno molta libertà nella realizzazione comportamento funzioni std::type_info.

Sto pensando di usare per confrontare i tipi di oggetto, quindi mi piacerebbe essere sicuri che:

  1. std::type_info::name deve restituire due stringhe differenti per due tipi diversi.

  2. std::type_info::before devo dire che Type1 è prima Type2 esclusivo o Type2 è prima Type1.

    // like this:
    typeid(T1).before( typeid(T2) ) != typeid(T2).before( typeid(T1) )
    
  3. Due diversa specializzazione della stessa classe template sono considerati tipi diversi.

  4. Due differenti typedef-initions dello stesso tipo sono dello stesso tipo.

E infine:

  • Dato std::type_info non è copiabile, come avrei potuto conservare type_infos da qualche parte (ad esempio: in un std::map)? L'unico modo per avere un std::type_info da qualche parte sempre assegnato (ad esempio: sullo stack o su una variabile statica / globale)? E utilizzare un puntatore ad esso

  • Quanto velocemente sono operator==, operator!= e before sulla maggior parte dei compilatori comuni? Credo che dovrebbero confrontare solo un valore. E quanto velocemente è typeid?

  • Ho una A classe con un virtual bool operator==( const A& ) const. Dal A ha molte sottoclassi (alcuni dei quali sono sconosciuti al momento della compilazione), mi piacerebbe overload che operatore virtuale in qualsiasi B sottoclasse in questo modo:

    virtual bool operator==( const A &other ) const {
      if( typeid(*this) != typeid(other) ) return false;
      // bool B::operator==( const B &other ) const // is defined for any class B
      return operator==( static_cast<B&>( other ) );
    }
    

    E 'questo un modo accettabile (e standard) per implementare tale operatore?

È stato utile?

Soluzione

Dopo una rapida un'occhiata alla documentazione, direi che:

  1. std :: :: type_info name restituisce sempre due stringhe differenti per due tipi diversi, altrimenti vuol dire che il compilatore si perdeva durante la risoluzione tipi e non si deve usare più.

  2. Riferimento dice: "prima del ritorno TRUE se il tipo precede il tipo di RHS nell'ordine collazione L'ordine di collazione è solo un ordine interno tenuto da una particolare implementazione e non è necessariamente correlate a rapporti di successione o ordine dichiarando. ". È quindi avere la garanzia che nessun tipo ha lo stesso rango nell'ordine collazione.

  3. Ogni istanza di una classe template è un diverso tipo. La specializzazione non fare eccezioni.

  4. Io non capisco quello che vuoi dire. Se qualcosa di media come avere typedef foo bar; in due unità distinte di compilazione e quel bar è lo stesso in entrambi, funziona in questo modo. Se vuoi dire typedef foo bar; typedef int bar;, non funziona (a meno che foo è int).

A proposito vostre altre domande:

  • Si dovrebbe memorizzare i riferimenti a std :: type_info, di avvolgere in qualche modo.
  • assolutamente idea circa le prestazioni, suppongo che gli operatori di confronto hanno tempo costante nonostante il tipo di complessità. Prima deve avere complessità lineare in funzione del numero di tipi diversi utilizzati nel codice.
  • Questo è davvero strano imho. Si dovrebbe sovraccaricare il operator== invece di Make IT virtuale e sostituirla.

Altri suggerimenti

standard 18.5.1 (Classe type_info):

Il type_info classe descrive tipo informazioni generate dal implementazione. Oggetti di questa classe memorizzare in modo efficace un puntatore ad un nome per il tipo, e di un valore codificato atto a confrontare due tipi di l'uguaglianza o l'ordine di collazione. Il nomi, regola la codifica, e fascicolazione sequenza per i tipi sono tutti non specificato e possono differire tra i programmi .

Dalla mia comprensione:

  1. Non hai questa garanzia per quanto riguarda std:type_info::name. La norma afferma soltanto che restituisce name un NTB implementazione definita , e credo che un conforme attuazione potrebbe benissimo tornare la stessa stringa per ogni tipo.
  2. Non lo so, e lo standard non è chiaro su questo punto, in modo da non fare affidamento su tale comportamento.
  3. che uno dovrebbe essere un preciso 'Sì' per me
  4. che uno dovrebbe essere un preciso 'Sì' per me

Per quanto riguarda la seconda serie di domande:

  • No, non è possibile memorizzare un type_info. Andrei Alexandrescu propone un involucro TypeInfo nella sua libro moderno C ++ design . Nota che gli oggetti restituiti da typeid hanno stoccaggio statico in modo da poter memorizzare in modo sicuro i puntatori, senza preoccuparsi di durata degli oggetti
  • Credo che si può supporre che il confronto type_info sono estremamente efficienti (non c'è davvero molto da confrontare).

È possibile memorizzare in questo modo.

class my_type_info
{
public:
     my_type_info(const std::type_info& info) : info_(&info){}
     std::type_info get() const { return *info_;}
private:
     const std::type_info* info_;
};

EDIT:

C ++ standard di 5.2.8.

Il risultato di un espressione typeid è un Ivalue di tipo statico const std :: type_info ...

Il che significa che è possibile utilizzarlo in questo modo.

my_type_info(typeid(my_type));

La funzione typeid restituisce un lvalue (non è temporanea) e quindi l'indirizzo del restituita type_info è sempre valido.

Le risposte attuali per le domande 1 e 2 sono perfettamente corrette, e sono essenzialmente solo dettagli per la classe type_info -. Inutile ripetere quelle risposte

Per domande 3 e 4, è importante capire che cosa è esattamente un tipo in C ++, e come si riferiscono ai nomi. Per cominciare, ci sono un sacco di tipi predefiniti, e quelli hanno nomi: int, float, double. Poi, ci sono alcuni tipi costruiti che fare non hanno nomi dei loro propri: const int, int*, const int*, int* const. Ci sono tipi di funzione int (int) e puntatore a funzione tipi int (*)(int).

A volte è utile per dare un nome ad un tipo senza nome, che è possibile utilizzare typedef. Ad esempio, typedef int* pint o typedef int (*pf)(int);. Questo introduce un nome, non un nuovo tipo.

Avanti sono definiti dall'utente tipi: le strutture, le classi, i sindacati. C'è una buona convenzione per dare loro i nomi, ma non è obbligatorio. Non aggiungere tale nome una con typedef, è possibile farlo direttamente: struct Foo { }; invece di typedef struct {} Foo;. E 'comune per avere definizioni di classe nelle intestazioni, che finiscono \ in più unità di traduzione. Ciò significa che la classe è definita più di una volta. Questo è ancora dello stesso tipo, e quindi non sono autorizzati a giocare trucchi con le macro per modificare le definizioni di membro di classe.

Una classe template è non un tipo, è una ricetta per i tipi. Due istanze di un singolo modello di classe sono tipi distinti se gli argomenti template sono diversi tipi (o valori). Questo funziona in modo ricorsivo:. Dato template <typename T> struct Foo{};, Foo<Foo<int> > è dello stesso tipo di Foo<Foo<Bar> > se e solo se Bar è un altro nome per il tipo int

type_info è implementazione definita in modo davvero non fare affidamento su di esso. Tuttavia, in base alle mie esperienze con g ++ e MSVC, le ipotesi 1,3 e 4 stretta ... non proprio sicuro di # 2.

C'è qualche motivo non è possibile utilizzare un altro metodo come questo?

template<typename T, typename U>
struct is_same       { static bool const result = false; };

template<typename T>
struct is_same<T, T> { static bool const result = true;  };

template<typename S, typename T>
bool IsSame(const S& s, const T& t) {   return is_same<S,T>::result; }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top