Casting zwischen void * und einen Zeiger auf member-Funktion
Ich bin derzeit mit GCC 4.4, und ich bin mir ziemlich Kopfschmerzen casting zwischen void*
und einen Zeiger auf member-Funktion. Ich bin versucht zu schreiben, eine einfach zu bedienende Bibliothek für das binden von C++ - Objekten zu einem Lua-interpreter, etwa so:
LuaObject<Foo> lobj = registerObject(L, "foo", fooObject);
lobj.addField(L, "bar", &Foo::bar);
Ich habe die meisten es getan, mit Ausnahme der folgenden Funktion (die ist auf eine bestimmte Funktion Unterschrift, bis ich eine chance habe, zu verallgemeinern):
template <class T>
int call_int_function(lua_State *L)
{
//this next line is problematic
void (T::*method)(int, int) = reinterpret_cast<void (T::*)(int, int)>(lua_touserdata(L, lua_upvalueindex(1)));
T *obj = reinterpret_cast<T *>(lua_touserdata(L, 1));
(obj->*method)(lua_tointeger(L, 2), lua_tointeger(L, 3));
return 0;
}
Für diejenigen von Ihnen nicht vertraut mit Lua lua_touserdata(L, lua_upvalueindex(1))
bekommt den ersten Wert zugeordnet ist, einen Verschluss (in diesem Fall, es ist der Zeiger auf member-Funktion) und gibt es als void*
. GCC beschwert sich, dass void*
-> void (T::*)(int, int)
ist ein Ungültiger Stimmen. Irgendwelche Ideen auf, wie man das umgehen kann?
+1 die oben... insbesondere Abschnitt 33.7 & 33.8
Nur aus Neugier, warum sind Sie versuchen zu speichern C-Funktionen in Lua userdata? wahrscheinlich gibt es ein sicherer Weg, um Ihr Ziel zu erreichen.
Sie können asm, um den job tun, wenn Sie wissen, die Plattform. C++ nicht meckern es dann. In einigen Fällen sinnvoll(z.B. testen von code). Einfach speichern Sie die func ptr in eine var, erstellen Sie eine void*, gehen in asm und kopieren Sie den Wert über.
InformationsquelleAutor | 2009-08-20
Du musst angemeldet sein, um einen Kommentar abzugeben.
Du kann nicht werfen einen Zeiger-auf-member
void *
oder zu jedem anderen "normalen" Zeiger-Typ. Zeiger-zu-member werden nicht korrigiert, wie regelmäßige Zeiger sind. Was Sie wahrscheinlich tun müssen, ist, wickeln Sie Ihre member-Funktion in einem regulären Funktion. Der C++ FAQ Lite dies erklärt in einigen Details. Das Hauptproblem ist, dass die Daten benötigt um einen Zeiger-auf-member ist nicht nur eine Adresse, und in der Tat variiert enorm basiert auf der compiler-Implementierung.Ich nehme an, Sie haben die Kontrolle über das, was der Benutzer Daten
lua_touserdata
zurück. Es kann nicht ein Zeiger-auf-member-da gibt es keine rechtliche Möglichkeit, diese Informationen wieder aus. Aber Sie haben auch einige andere Möglichkeiten:Die einfachste Wahl ist wahrscheinlich zu wickeln Sie Ihre member-Funktion in einer freien Funktion und Rückkehr. Dass freie Funktion sollte das Objekt als erstes argument. Siehe das code-Beispiel unten.
Verwenden eine Technik ähnlich der von Boost.Bind ' s mem_fun, um wieder eine function-Objekt, Sie können die Vorlage entsprechend auf. Ich sehe nicht, dass dies einfacher ist, aber es würde Sie verknüpfen die mehr Staat mit der Funktion zurück, wenn Sie Sie brauchte.
Hier ist ein umschreiben Ihrer Funktion mit der erste Weg:
Martin, ich habe geschult an diesem Punkt noch vor kurzem. Lassen Sie mich zeigen Sie an der Diskussion hier: stackoverflow.com/questions/1207106/....
Martin: Lesen Sie Auch die markierten link "variiert enorm": "codeproject.com/KB/cpp/FastDelegate.aspx. Zeiger auf member-Funktionen sind nicht unbedingt umgesetzt werden als Hinweise oder gar die gleiche Art von system zu system. Sie können Kombinationen aus einer Tabelle und einen index, voll auf thunks oder eine beliebige Anzahl von variant-Implementierungen.
Sprach zu schnell. Re-cant.
So habe ich in der ursprünglichen Frage :). Es ist eindeutig eine subtile Thema.
InformationsquelleAutor quark
Es ist möglich, konvertieren Zeiger auf member-Funktionen und-Attribute mit Hilfe der Gewerkschaften:
Konvertieren, legen Sie die Quell-Wert in einem Mitgliedstaat, und ziehen Sie die "target" - Wert aus der anderen.
Diese Methode ist zwar praktisch, ich habe keine Ahnung, ob das in jedem Fall funktioniert.
sizeof(void*) < sizeof(memberT classT::*)
; sopvoid
kann nicht repräsentieren allepmember
.Ich habe versucht, diese Methode mit dem MSVC November CTP. Ich habe eine
static_assert
um sicherzustellen, dasssizeof(u_ptm_cast::pmember) == sizeof(u_ptm_cast::pvoid)
. Es wird funktioniert in den meisten Situationen, z.B. beim pmember ist nicht-virtuelle, virtual oder wennclassT
ersetzt wird, für eine andere Klasse bei der Konvertierung zurück in eine member-Funktion-Zeiger. Allerdings, wennclassT
beschäftigt mehrfache Vererbung, der Zeiger ist in der Tat größer und die Bestätigung fehlschlägt.Unter GCC 4.7, alle member-Funktion-Zeiger angezeigt werden, die Größe von zwei regulären Zeigern. Buchhaltung für diese, indem Sie
pvoid
ein array der doppelten Größe, @paniq ' s Technik mit einemunion
funktioniert bei den gleichen Fällen wie bei der MS-compiler. Insgesamt aber, es ist eine ziemlich fragile Lösung und nicht viel in die Lua-binding-problem.Sie denken, wenn Sie mit " #pragma pointers_to_members( full_generality, multiple_inheritance ) funktionieren würde, wenn classT beschäftigen Mehrfachvererbung? msdn.microsoft.com/en-us/library/83cch5a6.aspx
Vielleicht, aber ich würde Folgen Sie @quark Ratschläge, um etwas wirklich tragbar.
InformationsquelleAutor paniq
Als workaround angesichts der Beschränkungen der Umwandlung von einer Zeiger-auf-member-Funktion
void*
könnten Sie wickeln die Funktion Zeiger auf einen kleinen Haufen-reservierte Struktur und einen Zeiger auf das struct in Ihre Lua-user-Daten:Ich bin nicht versiert mit der Lua so habe ich wahrscheinlich etwas übersehen im obigen Beispiel. Beachten Sie auch, wenn Sie diesen Weg gehen, müssen Sie zum verwalten der LuaUserData Zuweisung.
InformationsquelleAutor fbrereto
Anders als die Adresse eines nichtstatische member-Funktion, die einen Zeiger-auf-member mit einem komplizierten Darstellung, die Adresse einer statische member-Funktion ist in der Regel eine nur eine Maschine, die Adresse, kompatibel mit einer Umstellung auf
void *
.Wenn Sie zu binden, müssen Sie ein C++ nicht-statische member-Funktion auf eine C-oder C-ähnliche callback-Mechanismus basiert auf
void *
, was Sie können versuchen zu tun, ist schreiben eine statische wrapper statt.Den wrapper nehmen kann, die einen Zeiger auf eine Instanz als argument übergeben, und die Kontrolle an die nicht-statische member-Funktion:
Die callback-Schnittstelle hat, um eine Kontext-argument für den Durchgang der registrierten Benutzer-Daten. I. e. "bitte übergeben Sie mir mein Zeiger an, wenn Sie rufen Sie mich zurück". Wenn die callback-Schnittstelle hat dies nicht, es kann gehackt werden mit Trampoline. Sie können setzen Sie ein kleines Stück von Computer-code (Trampolin) an der Vorderseite des callback-Objekt, und, die Maschinen-code verwendet wird, da die callback-Funktion. Es berechnet die Objekt-Zeiger relativ zu seiner instruction pointer, wohl wissend, dass das Objekt in einem festen Abstand von seiner eigenen Adresse. Ruft dann die eigentliche Funktion.
InformationsquelleAutor Kaz
Hier ändern Sie einfach die Parameter der Funktion void_cast für Sie an Ihre Bedürfnisse anpassen:
Beispiel verwenden:
InformationsquelleAutor Karlo Miličević