Frage an STL GURUS!!!!!
-
Deswegen sagte ich es ja. Man kann in der Regel kein Objekt pushen, wenn man dessen Typen nicht kennt. Klar, man kann wieder
void*anwenden, aber ja... Schlussendlich weiss man gar nichts mehr.
-
Och, ich weiß gar nicht, ob das mit dem unbekannten Typ bei der Übergabe so ein Problem ist, schließlich nimmt list::push_back den Parameter ja per Referenz und nicht per Value. Ich denke eher, dass es am Funktionsaufruf scheitert.
-
Ist nicht standardkonform und dreckig, aber es funktioniert zumindest unter MSVC++ 2005 in Debug und Release:
#include <iostream> #include <list> #include <assert.h> #include <string> using namespace std; // Für alles, was mit reinterpret_cast nicht möglich ist: template<typename U,typename T> U forbidden_cast( T p ) { assert( sizeof(T) == sizeof(U) ); union Shared { T p1; U p2; }; Shared s; s.p1 = p; return s.p2; } // Führt die push_back-Aktion aus void makeWeirdPushBackCall( void* plist, void* pfunc, void* pval ) { struct Foo {}; // Als Parameter einfach eine const-Referenz auf irgendwas typedef void(Foo::*FooFuncPtr)( const int& ); FooFuncPtr func = forbidden_cast<FooFuncPtr>( pfunc ); Foo* foo = static_cast<Foo*>( plist ); // Die push_back-Funktion aufrufen (foo->*func)( *((int*)pval) ); } void main() { typedef std::string ValueType; std::list<ValueType> f; ValueType val = "123"; makeWeirdPushBackCall( &f, forbidden_cast<void*>(&std::list<ValueType>::push_back), &val ); // Liste ausgeben cout << f.size() << "\n"; for ( std::list<ValueType>::const_iterator i=f.begin(); i!=f.end(); ++i ) cout << *i << "\n"; }Ja, es ist dreckig, aber gar nicht so sehr, wie man denken mag. Jedenfalls in Bezug auf das aktuelle Szenario, wo std::list keine virtuellen Funktionen hat und push_back die Standard-Calling-Convention nutzt.
Der Code geht halt davon aus, dass
- der Compiler für die Aufrufestd::list<T> l; l.push_back( ... );und
struct Foo { void push_back(const int&); }; Foo l; l.push_back( ... );den selben Code erzeugt, dass
-
const T&undconst U&für alleTundUgleich repräsentiert werden (z.B. durch 'nen Pointer, afaik gängige Praxis unter den Compilern) und dass -
void(T::*)(const int&)verlust- und gefahrlos invoid*konvertiert werden kann und vice versa, dass
- std::list keine virtuellen Funktionen enthält und die Standard Calling-Convention benutzt und
- mehr fällt mir nicht ein.
Aber wie gesagt: Der Code ist nicht standard-konform und nur eine Spielerei.
-
-
Hey vielen vielen Dank für die schnellen Antworten an euch alle !!!!!
Sehr cooles Forum hier!!!@Badestrand: Hey Alter, vielen Dank für deine Antwort, genau so einen Mechanismus suche ich für mein kleines Reflection System.
Meinst du diese Version funktioniert auch mit dem GNU Compiler? Und ich weiß auch, dass das nicht der schöne Stil ist, aber es hilft mir gerade wirklich weiter
vielen Dank an euch alle!!!
gruß Tobber
-
Tobias Harley schrieb:
@Badestrand: Hey Alter, vielen Dank für deine Antwort, genau so einen Mechanismus suche ich für mein kleines Reflection System.
Meinst du diese Version funktioniert auch mit dem GNU Compiler? Und ich weiß auch, dass das nicht der schöne Stil ist, aber es hilft mir gerade wirklich weiter
Gern geschehen, wenn du dein Reflection System fertig hast, kannst du's hier ja auch mal vorstellen
Ob's mit dem GNU-Compiler klappt, puh, musst du wohl ausprobieren.
-
Badestrand schrieb:
// Für alles, was mit reinterpret_cast nicht möglich ist: template<typename U,typename T> U forbidden_cast( T p ) { assert( sizeof(T) == sizeof(U) ); union Shared { T p1; U p2; }; Shared s; s.p1 = p; return s.p2; }Was ist denn z.B. mit reinterpret_cast nicht möglich?
Und wo ist außer dem assert der wesentliche Unterschied?
-
pumuckl schrieb:
Was ist denn z.B. mit reinterpret_cast nicht möglich?
Und wo ist außer dem assert der wesentliche Unterschied?Ich hatte es nur kurz ausprobiert, aber die Umwandlung von Member-Function-Pointer nach void* wollte reinterpret_cast nicht machen.
-
hey also das ganze funktioniert echt super mit Visual Studio, leider beendet es der MinGW Compiler mit einer unhandled win32 exception. Aber vielleicht gibt es ja auch noch eine C++ Standart konforme(re) Lösung für dieses Problem, ich würde es gerne kompatibel zu mehreren Compilern halten?
grüsse
Tobber
-
Ja, gibt es, über Template-Parameter, ohne üble Hacks. Vielleicht schilderst Du mal, warum Du meinst, diesen Hack zu brauchen. Vielleicht kann man Dich dann davon überzeugen, dass dem nicht so ist.

-
Zwischen Datenzeigern (auch void*) und Funktionszeigern zu casten ist in C++ nicht erlaubt. Manche Compiler unterstützen es, aber wie gesagt, erlaubt ist es nicht.
Was spricht gegen die Verwendung von boost::function<> oder ähnlichem?
-
Hi,
ja gerne, also ich baue ein kleines Reflection System (oder versuche es), sieht "grob" so aus (ohne syntactic sugar)
class Test : public Object { public: Test(); ~Test(); private: int i; list<string> strList; public: void reflect( System* sys ) { sys->addClass( "Test" ); sys->addProperty( "i", TYPE_INTEGER, &i ); // mein problemkind. sys->addSTLProperty( "strList", TYPE_STL_LIST, /* zeiger auf container */ &strList, /* Memberfunctionpointer auf void* casten */ forbidden_cast <void*>( &list<string>::push_back ) ); } };Nun will ich mit nur einem (void*) Pointer auf eine Instanz (von Test), und der generierten Typinformation, Elemente in meine Lise (strList) einfügen. Was auch mit der von badestrand gezeigten Methode wunderbar funzt, aber leider nur im Visual Studio, der MinGW macht da nich mit.
Ich hoffe das Code-Stück stellt meine Problematik dar.
dank und gruß
Tobber
-
Mal ganz davon abgesehen dass ich nicht glaube dass das so eine gute Idee ist...:
boost::shared_ptr<void> pushBackFunctor(new boost::function<void (int)>(boost::bind(&list<string>::push_back, &strList, _1))); sys->addSTLProperty( "strList", TYPE_STL_LIST, &strList, pushBackFunctor);Jetzt castest du Datenzeiger, und das ist erlaubt.
-
BTW: bau dir doch gleich kleine Helper-Templates:
class WrappedProperty { public: WrappedProperty(char const* name): m_name(name) { } char const* GetName() const { return m_name; } virtual int GetTypeCode() const = 0; private: char const* m_name; }; template <class T> ScalarTypeCodeMap; template <> ScalarTypeCodeMap<int> { static const int TypeCode = 1; } template <> ScalarTypeCodeMap<char> { static const int TypeCode = 2; } // ... template <class T> WrappedScalar : public WrappedProperty { public: virtual int GetTypeCode() const { return ScalarTypeCodeMap<T>::TypeCode; } T value; }; class WrappedCollectionProperty : public WrappedProperty { public: virtual void PopFront() = 0; virtual void PopBack() = 0; virtual void Clear() = 0; virtual size_t GetSize() = 0; virtual size_t GetCapacity() = 0; }; // ...
-
BZW. noch eine Frage: was willst du mit diesem Reflection-System eigentlich erreichen?
-
hustbaer schrieb:
BZW. noch eine Frage: was willst du mit diesem Reflection-System eigentlich erreichen?
Frage ich mich gerade auch.. Wenn man da sowieso alles von Hand eintragen muss ist der Spass ja weg..
Ich denke mal, das man das mit Typlisten automatisch erledigen kann, allerdings wäre die Klassenerzeugung so etwas von umständlich und unhandlich, dass man es eigl. glatt vergessen kann..