type_info::name für unterschiedliche Klassen immer verschieden?
-
kurze frage: ist laut c++-standard folgende schlussfolgerung immer richtig:
typeid(A) != typeid(B) -> typeid(A).name() != typeid(B).name()
(A und B seien hierbei klassen, welche von einer abstrakten basisklasse abgeleitet wurden)
meine frage betrifft insbesondere verschiedene namensräume, templates usw...
kann ich auf allen (weitestgehend) standardkonformen compilern unter allen umständen davon ausgehen, dass type_info::name für unterschiedliche typen immer verschiedene ergebnisse liefert?
-
Soweit ich weiss, liefert
type_info::name()überhaupt gar keine Garantie in diesem Bereich. Es soll einfach nur ein lesbarer Name sein, mehr wird nicht spezifiziert. Also ich würde mich auf gar keinen Fall darauf verlassen!Grüssli
-
Nein, in der Norm steht nur, daß der Namen "implementation defined NTBS" ist. Das kann effektiv alles mögliche sein.
-
Es ist durchaus legal (und meines Wissens in irgendeinem Compiler auch so implementiert), dass name() einfach nur "" zurückliefert, egal bei welchem Typ...
-
typeid schrieb:
kurze frage: ist laut c++-standard folgende schlussfolgerung immer richtig:
typeid(A) != typeid(B) -> typeid(A).name() != typeid(B).name()
Ist das eher eine allgemeine Frage? Denn ich kann mir nicht ganz erklären, wozu du das brauchst. Du kannst ja
std::type_info-Instanzen direkt mit den Operatoren==und!=untereinander vergleichen.
-
Mit raw_name sollte es IMO garantiert sein.
(Unter Windows allerdings auch nur bedingt, sobald man DLLs verwendet.)
-
hustbaer schrieb:
Mit raw_name sollte es IMO garantiert sein.
Ist das nicht VC-spezifisch? Dann kannst du gleich name() verwenden, und dein Code funktioniert dafür auch mit GCC und BCC.
-
audacia schrieb:
hustbaer schrieb:
Mit raw_name sollte es IMO garantiert sein.
Ist das nicht VC-spezifisch? Dann kannst du gleich name() verwenden, und dein Code funktioniert dafür auch mit GCC und BCC.
Ist es, ja. Wusste ich aber nicht. Shame on me

-
Das ist jetzt zwar nur eine Meckerfrage die nichts ändern wird, aber:
Wieso kann man den zurückgegebenen Namen nicht mal standardisieren? Bei der typeid kann ich das ja noch verstehen, aber bei 'nem Namen? Einem String? Das würde die plattformunabhängige Serialisierung/Deserialisierung von Objekten deutlich vereinfachen.
-
Tachyon schrieb:
Wieso kann man den zurückgegebenen Namen nicht mal standardisieren? Bei der typeid kann ich das ja noch verstehen, aber bei 'nem Namen? Einem String? Das würde die plattformunabhängige Serialisierung/Deserialisierung von Objekten deutlich vereinfachen.
Meine Rede. (Und nebst anderen Defekten in C++ hier ausführlich diskutiert.)
-
Beim GCC (Linux) liefert type_info::name() jedenfalls nicht den eigentlichen Namen (warum denn eigentlich?). Beim MSVC schon.
#include <iostream> #include <string> #include <vector> #include <typeinfo> using namespace std; #define CompareTypes(a, b) if (typeid(a) == typeid(b)) \ cout << (#a) << " and " << (#b) << " are the same!\n"; \ else \ cout << (#a) << " and " << (#b) << " are NOT the same!\n"; \ cout << typeid(a).name() << " (" << (#a) << ") "; \ if (typeid(a).name() == typeid(b).name()) \ cout << "=="; \ else \ cout << "!="; \ cout << " " << typeid(b).name() << " (" << (#b) << ")\n\n" int main() { vector<char> VectorChar; vector<char> VectorChar2; vector<string> VectorString; string String; CompareTypes(VectorChar, VectorChar2); CompareTypes(VectorChar, VectorString); CompareTypes(VectorChar, String); CompareTypes(VectorString, String); return 0; }VectorChar and VectorChar2 are the same! St6vectorIcSaIcEE (VectorChar) == St6vectorIcSaIcEE (VectorChar2) VectorChar and VectorString are NOT the same! St6vectorIcSaIcEE (VectorChar) != St6vectorISsSaISsEE (VectorString) VectorChar and String are NOT the same! St6vectorIcSaIcEE (VectorChar) != Ss (String) VectorString and String are NOT the same! St6vectorISsSaISsEE (VectorString) != Ss (String)wie kommen die GCC-Hersteller auf diese Namen?
Gruss
Cartman
-
Nexus schrieb:
typeid schrieb:
kurze frage: ist laut c++-standard folgende schlussfolgerung immer richtig:
typeid(A) != typeid(B) -> typeid(A).name() != typeid(B).name()
Ist das eher eine allgemeine Frage? Denn ich kann mir nicht ganz erklären, wozu du das brauchst. Du kannst ja
std::type_info-Instanzen direkt mit den Operatoren==und!=untereinander vergleichen.ich kann leider type_info nicht in einem vektor o.ä. speichern (copy-konstruktor und zuweisung sind private), sondern nur das, was type_info::name zurückliefert. genau das bräuchte ich für die serialisierung, ich gehe schon einen umweg über nummern (um die compiler-abhängigen namen zu vermeiden), aber wenn ich mich nicht mal auf oben genannte bedingung verlassen kann ist das schon schade...

-
Eric Cartman schrieb:
wie kommen die GCC-Hersteller auf diese Namen?
Das sind glaube ich die Linkersymbole.
Im Allgeminen finde ich typeid ziemlich nutzlos. Eventuell kann der Threadstarter folgenden Trick gebrauchen:
unsigned make_id(){ static unsigned id = 0; return id++; } template<class T> unsigned get_type_id(){ static unsigned id = make_id(); return id; }Um typeid und type_info gehört meiner Meinung nach einen großen Bogen gemacht.
-
typeid schrieb:
ich kann leider type_info nicht in einem vektor o.ä. speichern (copy-konstruktor und zuweisung sind private), sondern nur das, was type_info::name zurückliefert. genau das bräuchte ich für die serialisierung, ich gehe schon einen umweg über nummern (um die compiler-abhängigen namen zu vermeiden), aber wenn ich mich nicht mal auf oben genannte bedingung verlassen kann ist das schon schade...

Wie wäre es, wenn du
std::type_infokapselst?#include <typeinfo> class TypeInfo { // Attributes // private: std::type_info const* m_type; // Constructors // public: TypeInfo(std::type_info const& type) : m_type(&type) { } // Methods // public: std::type_info const& get_type() const { return *m_type; } }; bool operator ==(TypeInfo const& lhs, TypeInfo const& rhs) { return lhs.get_type() == rhs.get_type(); } bool operator !=(TypeInfo const& lhs, TypeInfo const& rhs) { return lhs.get_type() != rhs.get_type(); } bool operator <(TypeInfo const& lhs, TypeInfo const& rhs) { return lhs.get_type().before(rhs.get_type()); }Oder irgendetwas in diese Richtung ...
Grüssli
-
@ben04: hmm, schaut schon mal gut aus. jetzt brauche ich nur noch einen trick, wie ich die "echte" klassen-id von einem objekt bekomme, auf das ich über einen basisklassenzeiger zugreife. ich möchte nicht für jede abgeleitete klasse eine methode überschreiben, die eigentlich doch immer das gleiche tut:
class base { //... public: virtual unsigned int get_class_id() const {return get_type_id<base>();} }; class derived : public base { //... public: virtual unsigned int get_class_id() const {return get_type_id<derived>();} };das muss doch auch irgendwie eleganter gehen, oder? schließlich kann es schnell passieren, dass man das überschreiben der methode mal vergisst...

-
Folgendes geht:
class Base{ public: virtual unsigned get_id()const=0; }; template<class T> class DeriveFromBase:public Base{ public: virtual unsigned get_id()const{ return get_type_id<T>(); } }; class Child:public DeriveFromBase<Child>{ };Dadurch, dass man this nach T* in DeriveFromBase castet kann man noch viele schöne Sachen machen. Zum Beispiel eine Clonefunktion welche den (möglicherweise implizit erzeugten) Kopiekonstruktor der Kindklasse verwendet.
Alternativ kann man auch eine Makro DEFAULT_METHODS definieren und in jede Childklasse reinpacken. Dieser Ansatz erlaubt es zusätzlich den Klassennamen portabel aber nicht eindeutig in einen String zu kriegen.
-
Dravere schrieb:
TypeInfo(std::type_info const& type) : m_type(&type) { }hmm, hier sehe ich das problem, dass der zeiger zu einem späteren zeitpunkt ins leere verweisen kann, nämlich nachdem der block verlassen wurde, in dem dieser konstruktor aufgerufen wurde. oder garantiert mir der standard, dass die adresse des von typeid zurückgegebenen objektes immer gültig bleibt? wäre schön...
-
C++ Standard 98:
Kapitel 5.2.8 Type Identification
Abschnitt 1The result of a typeid expression is an lvalue of static type
const std::type_info(18.5.1) and dynamic typeconst std::type_infoorconstname where name is an implementation-defined class derived fromstd::type_infowhich preserves the behavior described in 18.5.1. The lifetime of the object referred to by the lvalue extends to the end of the program. Whether or not the destructor is called for thetype_infoobject at the end of the program is unspecified.Grüssli
-
Du kannst auch gleich Boost.Pointer Container verwenden, die stellen keine Anforderungen bezüglich Kopierbarkeit. Oder Standardcontainer mit
shared_ptr.
-
Nexus schrieb:
Du kannst auch gleich Boost.Pointer Container verwenden, die stellen keine Anforderungen bezüglich Kopierbarkeit. Oder Standardcontainer mit
shared_ptr.Welche dann ein
deleteauf den Zeiger vonstd::type_infodurchführen. Huiiiii, schöööönes Feuerwerk
Ok, beimshared_ptrkönnte man das abschalten. Aber der Overhead vomshared_ptrist völlig unnötig. Es muss keine Referenzzählung stattfinden. Die Verwendung von Boost.PtrContainer oder Boost.SmartPointer ist hier völlig fehl am Platz.Grüssli