primitives instanceof
-
Dann ist sowas also nicht möglich, d.h. schmeist ne exception?
int main() { boost::any asd = (int)5; long value = boost::any_cast< long >( asd ); std::cout<< value<<std::endl; std::cin.get(); }
-
So ist es.
-
Dann bin ich mir ziemlich sicher dass es eine Möglichkeit gibt, das ohne dynamic_cast zu bauen.
EDIT: Hab jetzt grade wohl nicht genug Zeit, aber bis heute abend werd ich mal schauen ob ichs hinbekomm
-
So, hier mal ne Demo, bei der man aber meinen Ansatz denk ich erkennt:
#include <iostream> unsigned int nextID() { static unsigned int current_id = 0 ; ++current_id; return current_id; } template< class Type > unsigned int typeID() { static unsigned int id = nextID(); return id; } class AnyTypeWrapper { public: virtual ~AnyTypeWrapper() { } virtual AnyTypeWrapper *clone() = 0; virtual void *getObjectMemory() = 0; }; template< class T > class TypeWrapper : public AnyTypeWrapper { private: T obj; public: TypeWrapper( const T &Object ) : obj( Object ) { } AnyTypeWrapper *clone() { return new TypeWrapper< T >( obj ); } void *getObjectMemory() { return &obj; } }; class any { private: unsigned int id; AnyTypeWrapper *wrapper; public: any() { id = 0; wrapper = 0; } template< class T > any( const T &Object ) { id = typeID< T >(); wrapper = new TypeWrapper< T >( Object ); } ~any() { delete wrapper; } template< class T > friend T any_cast( any &any_instance ) { if( typeID< T >() == any_instance.id ) { return *reinterpret_cast< T* >( any_instance.wrapper->getObjectMemory() ); } else { throw 1; } } }; int main() { any anything = (int) 5; try { any_cast< int >( anything ); std::cout<< "int" <<std::endl; }catch(...) { std::cout<< "not int" <<std::endl; } try { any_cast< long >( anything ); std::cout<< "long" <<std::endl; }catch(...) { std::cout<< "not long" <<std::endl; } std::cin.get(); }
-
Abgesehen davon, dass du hier den falschen Cast verwendest, siehts richtig aus.
-
welcher falsche cast?
-
Da gehört ein static_cast hin statt reinterpret_cast

-
Das ist aber ein void*, den ich da caste.
-
Von und zu void* (wobei zu void* auch implizit geht) wird mit static_cast gecastet - richtig :p
-
GorbGorb schrieb:
Das ist aber ein void*, den ich da caste.
static_cast castet void* von und zu anderen Zeigertypen.

-
Wieder was gelernt

Was kostet denn eigentlich ein dynamic_cast im Vergleich zu einem if? (bzw. lohnt sich meine Version im allgemeinen?)
EDIT: Meine natürlich performance mäßig
-
@GorbGorb:
Ich habe vor einiger Zeit etwas ziemlich ähnliches geschrieben (habe mir deine Lösung jetzt nicht im Detail angeschaut):extern int t_id_counter; template<typename T> int GetTypeID() { static int i = -1; if(i == -1) { i = t_id_counter; ++t_id_counter; } return i; } class PtrManagerBase { PtrManagerBase(PtrManagerBase const &); PtrManagerBase &operator=(PtrManagerBase const &); public: PtrManagerBase(){} virtual ~PtrManagerBase(){} virtual void *Get() = 0; virtual PtrManagerBase *Copy() = 0; }; template<typename T> class PtrManager : public PtrManagerBase { T *ptr; PtrManager(PtrManager<T> const &); PtrManagerBase &operator=(PtrManager<T> const &); public: PtrManager(T *in) : ptr(in){} virtual ~PtrManager() { delete ptr; } virtual void *Get() { return static_cast<void *>(ptr); } virtual PtrManagerBase *Copy() { return new PtrManager<T>(new T(*ptr)); } }; class AnyType { PtrManagerBase *ptr_mgr; int t_id; public: AnyType(); template<typename T> AnyType(T const &in) : ptr_mgr(new PtrManager<T>(new T(in))), t_id(GetTypeID<T>()) { } AnyType(AnyType const &in); AnyType &operator=(AnyType const &in); virtual ~AnyType(); template<typename T> void Set(T const &in) { delete ptr_mgr; ptr_mgr = new PtrManager<T>(new T(in)); t_id = GetTypeID<T>(); } template<typename T> bool Is() { return t_id == GetTypeID<T>(); } template<typename T> T Get() { return *(static_cast<T *>(ptr_mgr->Get())); } }; //und das in die C++-Datei int t_id_counter = 0; AnyType::AnyType() : ptr_mgr(NULL), t_id(-1) { } AnyType::AnyType(AnyType const &in) : ptr_mgr(NULL), t_id(in.t_id) { if(in.ptr_mgr != NULL) { ptr_mgr = in.ptr_mgr->Copy(); } } AnyType &AnyType::operator=(AnyType const &in) { delete ptr_mgr; if(in.ptr_mgr == NULL) ptr_mgr = NULL; else ptr_mgr = in.ptr_mgr->Copy(); t_id = in.t_id; return *this; } AnyType::~AnyType() { delete ptr_mgr; }
-
Schon wieder so ein reinterpret_cast ala void* :p
-
Naja, das Resultat ist ja das Gleiche. Und irgendwie macht es ja auch (in natürlicher Sprache) Sinn, dass man "irgendetwas" neu interpretiert als "XY".
Ich hab mir mal die source zu boost::any angeschaut, und es sieht so aus, als ob die sich in any_cast per virtual function eine typeid von *content holen, die sie dann mit operator== mit typeid( ArgumentType ) vergleichen. Ich bin mir sehr sicher, dass das mit meiner Version deutlich schneller geht (hab grade im gcc getestet, und so wie es aussieht braucht eine typeid-comparison etwa 5x so lang wie ein int Vergleich). Vielleicht arbeite ich das noch weiter aus und schicks den boost-Leuten mal, hoffentlich wird was draus. Obwohl es natürlich sehr unwahrscheinlich ist, dass jemand der mit boost::any arbeitet groß auf performance achtet^^.
-
GorbGorb schrieb:
Vielleicht arbeite ich das noch weiter aus und schicks den boost-Leuten mal, hoffentlich wird was draus. Obwohl es natürlich sehr unwahrscheinlich ist, dass jemand der mit boost::any arbeitet groß auf performance achtet^^.
Ich habe mich das auch gefragt, glaube aber weniger, dass die boost-Leute diese doch noch einigermaßen naheliegende Lösung (immerhin sind wir beide draufgekommen) übersehen habe.
314159265358979 schrieb:
Schon wieder so ein reinterpret_cast ala void* :p
Mist, den anderen hatte ich schon abgeändert. So, jetzt ist es aber editiert.
-
GorbGorb schrieb:
Naja, das Resultat ist ja das Gleiche.
Da wäre ich mir nicht so sicher. Wenn
static_castgeht, ziehe es vor.GorbGorb schrieb:
Ich bin mir sehr sicher, dass das mit meiner Version deutlich schneller geht (hab grade im gcc getestet, und so wie es aussieht braucht eine typeid-comparison etwa 5x so lang wie ein int Vergleich). Vielleicht arbeite ich das noch weiter aus und schicks den boost-Leuten mal, hoffentlich wird was draus.
Vielleicht solltest du zuerst ein paar Bugs beseitigen (Kopiersemantik). Und etwas ausführlicher und in verschiedenen Situationen auf verschiedenen Compilern testen. Und dann gibts noch heimtückischere Fallen, z.B. die fehlende Threadsicherheit beim Zugriff auf
static-Objekte. Generell würde ich vielleicht eher zuerst in der Boost-Mailingliste eine Diskussion starten
Ausserdem könntest du möglicherweise die Performance weiter optimieren, indem du auf die
AnyTypeWrapper-Klasse verzichtest und stattdessen direktvoid*und Funktionszeiger verwendest. Macht auch den Code kürzer.Aber die Idee mit automatisch vergebenen Integer-IDs für Typen ist echt gut. Ich muss damit unbedingt mal herumexperimentieren. Ich habe nämlich das Problem, dass meine Dynamic-Dispatchers elend langsam sind, und der Grossteil der Zeit bei
std::type_info-Vergleichen verloren geht.
-
Nexus schrieb:
Ich habe nämlich das Problem, dass meine Dynamic-Dispatchers elend langsam sind, und der Grossteil der Zeit bei
std::type_info-Vergleichen verloren geht.Alexandrescu hat einen O(1) Dispatcher, wenn ich mich recht erinnere

-
314159265358979 schrieb:
Alexandrescu hat einen O(1) Dispatcher, wenn ich mich recht erinnere

Ja, aber der ist intrusiv. So einen baue ich vielleicht auch eines Tages, aber ich brauche nebenbei auch eine Version, die ohne Veränderung bestehender Klassen auskommt.
Aber ich sehe gerade, eins habe ich nicht bedacht: Um eine virtuelle Funktion oder RTTI komme ich nicht herum, falls ich zur Laufzeit die Typ-ID eines Objekts herausfinden will. Die Integer-Lösung bringt mir hier also nicht allzu viel. Aber vielleicht anderswo...

-
Klassen in der Skriptsprache sind nicht geplant. Ich meinte im Startpost, dass ich beliebige C++-Klassen im Container speichern können will.
Es werden also nur feste Typen erlaubt sein.@ 314159265358979:
Type Erasure
Wo ist dabei der Vorteil gegenüber boost::any?
boost::variadic
Ich habe die which()-Methode übersehen. Mit der wäre das natürlich möglich.
Anderes Problem: Dieser Artikel sagt mir, dass Visual Studio noch keine Variadic Templates unterstüzt.
Außerdem sehe ich immer noch nicht den Zusammenhang zum Visitor Pattern.@ wxSkip: Ich verstehe nicht, was das mit dem Problem zu tun hat? Oder beziehst du das auf Klassen + Member?
@ Ethon: Unions erlauben aber keine nicht-PODs.
@ krümelkacker: Ich habe nie von beliebig vielen Typen geredet, sondern nur von beliebigen Typen

-
Zum Visitor Pattern: Boost lässt dich mit apply_visitor einen Visitor auf die Variant anwenden. Nehmen wir an, in deiner Sprache steht der Ausdruck "a + b". Je nachdem, welchen Typ deine Variablen haben, kann das verschiedenes bedeuten. Zuerst stellst du fest, dass a z.B. ein string ist. Jetzt lässt du einen visitor<string> über b laufen. Ist b ebenfalls ein string, dann kannst du diesen direkt zurückgeben. Ist b ein int, dann kannst du ihn implizit konvertieren und zurückgeben. Ist b etwas anderes, könntest du eine Exception werfen. Mit dem Visitor pattern könnte man hier also Konvertierungen umsetzen.
Was Type Erasure angeht hatte ich ähnliche Gedanken, aber mitterweile denke ich, dass boost::variant am geeignetsten ist.