La conversion entre les void * et un pointeur de fonction membre
Je suis actuellement en utilisant GCC 4.4, et je suis tout à fait avoir le mal de tête de coulée entre void*
et un pointeur vers une fonction membre. Je suis en train d'écrire un facile-à-utilisation de la bibliothèque pour la liaison des objets en C++ d'un interpréteur Lua, comme suit:
LuaObject<Foo> lobj = registerObject(L, "foo", fooObject);
lobj.addField(L, "bar", &Foo::bar);
J'ai la plupart de le faire, sauf pour la fonction suivante (qui est spécifique à un certain signature de fonction jusqu'à ce que j'ai une chance de généraliser):
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;
}
Pour ceux peu familiers avec Lua, lua_touserdata(L, lua_upvalueindex(1))
obtient la première valeur associée à un dispositif de fermeture (dans ce cas, c'est le pointeur de fonction membre) et la retourne comme une void*
. GCC se plaint que void*
-> void (T::*)(int, int)
est pas valide en fonte. Des idées comment contourner ce problème?
+1 ci-dessus... en particulier l'article 33.7 & 33.8
Juste par curiosité, pourquoi essayez-vous de stocker des fonctions C dans Lua userdata comme ça? il y a probablement un moyen plus sûr d'atteindre votre objectif.
Vous pouvez utiliser l'asm pour faire le travail si vous connaissez la plate-forme. C++ n'est pas salope sur elle alors. Utile dans certains cas(tels que les tests de code). Il suffit de stocker la touche func ptr dans un var, créer un void*, aller en asm et copier la valeur.
OriginalL'auteur | 2009-08-20
Vous devez vous connecter pour publier un commentaire.
Vous ne peut pas lancer un pointeur vers membre de
void *
ou de tout autre "régulier" de type pointeur. Les pointeurs-à-membres ne sont pas les adresses de la façon régulière les pointeurs sont. Ce que vous avez très probablement besoin de faire est d'envelopper votre fonction membre dans une fonction régulière. Le C++ FAQ Lite explique cette dans le détail. Le principal problème est que les données nécessaires pour mettre en œuvre un pointeur de membre n'est pas seulement une adresse, et en fait varie énormément basé sur le compilateur de mise en œuvre.Je présume que vous avez le contrôle sur ce que les données de l'utilisateur
lua_touserdata
est de retour. Il ne peut pas être un pointeur-à-membre depuis il n'y a pas un moyen légal d'obtenir cette information. Mais vous n'avez d'autres choix:Le plus simple choix est probablement pour envelopper votre fonction membre dans une fonction libre et de retour que. Cette fonction doit prendre l'objet en tant que premier argument. Consultez l'exemple de code ci-dessous.
Utiliser une technique similaire à celle de Coup de pouce.De Bind mem_fun pour retourner un objet de fonction, vous pouvez le modèle de façon appropriée. Je ne vois pas que c'est plus facile, mais ce serait vous permettent d'associer le plus avec le retour de la fonction si vous avez besoin de.
Voici une réécriture de votre fonction à l'aide de la première méthode:
Martin, je suis instruit sur ce point récemment. Permettez-moi de vous pointer à la discussion ici: stackoverflow.com/questions/1207106/....
Martin: lire Aussi le lien marqué "variaient énormément": codeproject.com/KB/cpp/FastDelegate.aspx. Les pointeurs de fonctions membres ne sont pas nécessairement mis en œuvre comme des pointeurs, ni même de la même manière à partir d'un système à l'autre. Ils peuvent être des combinaisons d'une table et d'un index, une sur les thunks ou de l'un quelconque d'un certain nombre de variantes de mise en œuvre.
Parlé trop vite. Re-cant.
Ainsi ai-je dans cette question d'origine :). C'est clairement une subtile sujet.
OriginalL'auteur quark
Il est possible de convertir le pointeur de membre de fonctions et d'attributs à l'aide des syndicats:
À convertir, mettre la valeur de la source dans un membre, et tirez sur la cible de la valeur de l'autre.
Bien que cette méthode est pratique, je n'ai aucune idée de si ça va fonctionner dans tous les cas.
sizeof(void*) < sizeof(memberT classT::*)
; ainsipvoid
ne peuvent pas représenter touspmember
.J'ai essayé cette approche avec la MSVC novembre CTP. J'ai ajouté un
static_assert
pour s'assurer quesizeof(u_ptm_cast::pmember) == sizeof(u_ptm_cast::pvoid)
. dans la plupart des situations, par exemple lorsque pmember est non-virtuel, virtuel ou lorsqueclassT
est remplacé par un autre de la classe lors de la conversion de retour pour un membre de pointeur de fonction. Toutefois, siclassT
emploie l'héritage multiple, le pointeur est en effet plus grand et l'assertion échoue.Sous GCC 4.7, tous les pointeurs de fonction semble être de la taille de deux pointeurs. La comptabilité pour ce faire,
pvoid
un tableau de double de la taille, @paniq de la technique faisant appel à ununion
travaille pour le même cas qu'avec le MS compilateur. Mais dans l'ensemble, il est assez fragile solution et pas beaucoup d'utilisation en Lua liaison problème.Vous pensez que si l'ajout de #pragma pointers_to_members( full_generality, multiple_inheritance ) si classT employer l'héritage multiple? msdn.microsoft.com/en-us/library/83cch5a6.aspx
Peut-être, mais je voudrais suivre @quark conseils pour obtenir quelque chose de vraiment portable.
OriginalL'auteur paniq
Comme une solution de contournement, compte tenu des restrictions de la coulée d'un pointeur-à-membres de la fonction de
void*
vous pouvez rassembler le pointeur de fonction dans un petit tas-structure allouée et de mettre un pointeur vers cette structure dans votre Lua données de l'utilisateur:Je ne suis pas calée avec Lua donc j'ai probablement oublié quelque chose dans l'exemple ci-dessus. Gardez à l'esprit, aussi, si vous suivez cette voie, vous devrez gérer la LuaUserData de l'allocation.
OriginalL'auteur fbrereto
À la différence de l'adresse d'un non fonction membre, qui est un pointeur de type de membre avec un complexe de représentation, l'adresse d'un statique fonction membre est généralement juste une machine d'adresse, compatible avec une conversion
void *
.Si vous avez besoin de lier un C++ non statique de la fonction de membre d'un C ou C-comme mécanisme de rappel basé sur
void *
, ce que vous pouvez essayer de faire est d'écrire un statique wrapper à la place.Le wrapper peut prendre un pointeur vers une instance comme argument, et de passer le contrôle à la fonction membre non statique:
L'interface de rappel doit avoir un contexte argument pour le passage d'un utilisateur inscrit de données. I. e". merci de me passer de mon pointeur lorsque vous appelez moi". Si l'interface de rappel n'a pas cela, il peut être piraté avec des trampolines. Vous pouvez mettre un petit morceau de code machine (le trampoline) à l'avant de l'objet de rappel, et que le code machine est utilisée comme fonction de rappel. Il calcule le pointeur d'objet par rapport à son pointeur d'instruction, sachant que l'objet est fixe à un décalage à partir de sa propre adresse. Elle appelle ensuite la fonction réelle.
OriginalL'auteur Kaz
Ici, il suffit de changer les paramètres de la fonction void_cast pour s'adapter à vos besoins:
exemple d'utilisation:
OriginalL'auteur Karlo Miličević