Frage

Ich weiß, dass Compiler haben viel Freiheit std::type_info Funktionen Verhalten bei der Umsetzung.

Ich denke an es mit Objekttypen zu vergleichen, so dass ich sicher sein möchte, dass:

  1. std::type_info::name müssen zwei verschiedenen Saiten für zwei verschiedene Typen zurück.

  2. std::type_info::before muss, dass Type1 sagen vor Type2 Exklusiv-Oder Type2 heißt vor Type1.

    // like this:
    typeid(T1).before( typeid(T2) ) != typeid(T2).before( typeid(T1) )
    
  3. Zwei unterschiedliche Spezialisierung der gleichen Template-Klasse werden verschiedene Arten betrachtet.

  4. Zwei verschiedene typedef-initions vom gleichen Typ sind vom gleichen Typ.

Und schließlich:

  • Da std::type_info nicht kopierbar ist, wie könnte ich speichern type_infos irgendwo (zB: in einem std::map)? Der einzige Weg, einen std::type_info immer zugewiesen irgendwo zu haben (zB: auf dem Stack oder auf einer statische / globalen Variable)? Und einen Zeiger darauf verwenden

  • Wie schnell sind operator==, operator!= und before auf gängigste Compiler? Ich denke, sie sollten nur einen Wert vergleichen. Und wie schnell ist typeid?

  • Ich habe eine Klasse A mit einem virtual bool operator==( const A& ) const bekam. Da A viele Subklassen bekommen hat (von denen einige zum Zeitpunkt der Kompilierung unbekannt sind), würde ich auf diese Weise, dass die virtuellen Betreiber in jeder Unterklasse B Überlastung:

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

    Ist dies eine akzeptable (und Standard) Art und Weise solchen Operator zu implementieren?

War es hilfreich?

Lösung

Nach einem kurzen Blick auf die Dokumentation, das würde ich sagen:

  1. std :: type_info :: name gibt immer zwei verschiedenen Saiten für zwei verschiedene Typen, sonst bedeutet es, dass der Compiler selbst verloren Typen, während die Lösung, und Sie sollten es nicht mehr verwendet werden.

  2. Referenz sagt: „vor gibt true zurück, wenn der Typ geht der Typ von rhs in der Sortierreihenfolge Die Sortierreihenfolge nur eine innere Ordnung durch eine spezielle Implementierung gehalten ist und nicht notwendigerweise auf Vererbung Beziehungen oder zu erklären, um zusammen. .“ Sie deshalb die Garantie haben, dass keine Typen den gleichen Rang in der Sortierreihenfolge haben.

  3. Jede Instantiierung einer Template-Klasse ist eine andere Art. machen Spezialisierung keine Ausnahmen.

  4. Ich verstehe wirklich nicht, was Sie meinen. Wenn Sie meinen, so etwas wie typedef foo bar; in zwei getrennten Sammlung Einheiten und Bar in beiden gleich ist, funktioniert es so. Wenn Sie meinen, typedef foo bar; typedef int bar;, es funktioniert nicht (außer wenn foo ist int).

Sie über Ihre andere Fragen:

  • Sie sollten Referenzen speichern, um std :: type_info, wrap es irgendwie.
  • Absolut keine Ahnung von Leistung, Ich gehe davon aus, dass Vergleichsoperatoren haben konstante Zeit trotz der Art, Komplexität. Vor müssen lineare Komplexität haben, abhängig von der Anzahl der verschiedenen Arten in Ihrem Code verwendet.
  • Das ist wirklich seltsam imho. Sie sollten Ihre operator== statt make es virtuell überlasten und sie außer Kraft setzen.

Andere Tipps

Standard 18.5.1 (Klasse type_info):

Die Klasse type_info beschreibt Typ Informationen, die von der erzeugten Implementierung. Objekte dieser Klasse speichern effektiv einen Zeiger auf einen Namen für den Typ, und ein codierter Wert geeignet für zwei Arten für den Vergleich Gleichheit oder Sortierordnung. Die Namen, kodieren Regel und Datenabgleichs Sequenz für Typen sind alle nicht näher bezeichnet und kann zwischen den Programmen unterscheiden .

Von meinem Verständnis:

  1. Sie haben nicht diese Garantie in Bezug auf std:type_info::name. Die Norm nur besagt, dass name kehrt eine Implementierung definiert NTBs , und ich glaube, eine konforme Implementierung könnte die gleiche Zeichenfolge für jede Art sehr gut zurück.
  2. Ich weiß es nicht, und der Standard ist in diesem Punkt nicht klar, so dass ich nicht auf ein solches Verhalten verlassen würde.
  3. Das sollte man ein definitiv sein ‚Ja‘ für mich
  4. Das sollte man ein definitiv sein ‚Ja‘ für mich

Im Hinblick auf die zweite Reihe von Fragen:

  • Nein, Sie können nicht type_info speichern. Andrei Alexandrescu schlägt eine TypeInfo Wrapper in seiner Moderne C ++ Entwurf Buch. Beachten Sie, dass die Objekte von typeid zurückgegeben haben statische Speicher , so dass Sie sicher Zeiger ohne sich Gedanken über Objektlebensdauer speichern
  • Ich glaube, Sie, dass type_info Vergleich annehmen kann, sind extrem effizient (es ist wirklich nicht viel vergleichen).

Sie können es wie folgt speichern.

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 5.2.8.

Das Ergebnis eines typeid Ausdruck ist ein L-Wert von statischer Typ const std :: type_info ...

Das bedeutet, Sie es wie folgt verwenden können.

my_type_info(typeid(my_type));

Die typeid Funktion gibt einen L-Wert (es ist nicht zeitlich begrenzt ist) und damit die Adresse der zurück type_info immer gültig ist.

Die aktuellen Antworten auf die Fragen 1 und 2 sind vollkommen richtig, und sie sind im wesentlichen Details nur für die type_info Klasse -. Keinen Sinn darin, diese Antworten zu wiederholen

Für Fragen 3 und 4, ist es wichtig zu verstehen, was genau ein Typ in C ++, und wie sie sich auf Namen. Für den Anfang gibt es eine ganze Reihe von vordefinierten Typen, und die haben Namen: int, float, double. Als nächstes gibt es einige Arten konstruiert, die tun nicht haben eigene Namen: const int, int*, const int*, int* const. Es gibt Funktionstypen int (int) und Funktionszeigertypen int (*)(int).

Es ist manchmal nützlich, einen Namen zu einer nicht genannten Art zu geben, was möglich ist, typedef verwenden. Zum Beispiel typedef int* pint oder typedef int (*pf)(int);. Dies führt zu einem Namen, nicht ein neuer Typ.

Als nächstes sind benutzerdefinierte Typen: structs, Klassen, Gewerkschaften. Es gibt eine gute Konvention ihnen Namen zu geben, aber es ist nicht zwingend notwendig. Mach doch nicht so ein Name mit typedef hinzugefügt haben, können Sie dies direkt: struct Foo { }; statt typedef struct {} Foo;. Es ist üblich, von Klassendefinitionen in Header zu haben, die mehreren Übersetzungseinheiten am Ende \ in. Das bedeutet die Klasse definiert ist mehr als einmal. Dies ist immer noch die gleiche Art, und deshalb dürfen Sie nicht Tricks mit Makros spielen, um die Klassenelementdefinitionen zu ändern.

Eine Template-Klasse ist nicht eine Art, es ist ein Rezept für Typen. Zwei instantiations einer einzelnen Klasse-Vorlage sind unterschiedliche Typen, wenn die Vorlage Argumente verschiedene Typen (oder Werte) sind. Dies funktioniert rekursiv. Da template <typename T> struct Foo{};, Foo<Foo<int> > vom gleichen Typ wie Foo<Foo<Bar> > ist, wenn und nur wenn Bar ist ein anderer Name für den Typ int

type_info ist Implementierung definiert, so würde ich wirklich nicht auf sie verlassen. Doch auf Grund meiner Erfahrungen mit g ++ und MSVC, Annahmen 1,3 und 4 halten ... nicht wirklich sicher # 2.

Gibt es einen Grund, warum Sie nicht eine andere Methode wie diese verwenden kann?

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; }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top