J’essaie de trouver l’adresse d’une fonction à partir d’un std :: function.
La première solution était:
size_t getAddress(std::function function) { typedef void (fnType)(void); fnType ** fnPointer = function.target(); return (size_t) *fnPointer; }
Mais cela ne fonctionne que pour les fonctions avec signature (void ()), car j’ai besoin pour cette fonction de signature (void (Type &)), j’ai essayé de le faire.
template size_t getAddress(std::function function) { typedef void (fnType)(T &); fnType ** fnPointer = function.target(); return (size_t) *fnPointer; }
Et je reçois “Erreur – attendu ‘(‘ pour la conversion ou le type de construction de type fonction”
Mise à jour: Est-il possible de capturer l’adresse de la classe de membre? pour les membres de la classe, j’utilise:
template size_t getMemberAddress(std::function & executor) { typedef Return (Clazz::*fnType)(Arguments...); fnType ** fnPointer = executor.template target(); if (fnPointer != nullptr) { return (size_t) * fnPointer; } return 0; }
Mise à jour: pour capturer le lambda que j’utilise
template struct function_traits : public function_traits { }; template struct function_traits { typedef ReturnType (*pointer)(Args...); typedef std::function function; }; template typename function_traits::function to_function (Function & lambda) { return static_cast<typename function_traits::function>(lambda); } template size_t getAddress(Lambda lambda) { auto function = new decltype(to_function(lambda))(to_function(lambda)); void * func = static_cast(function); return (size_t)func; } std::cout << getAddress([] { std::cout << "Hello" << std::endl;}) << std::endl;
Vous devez utiliser le mot clé template
lorsque vous appelez target:
#include #include template size_t getAddress(std::function f) { typedef void (fnType)(T &); fnType ** fnPointer = f.template target(); return (size_t) *fnPointer; } void foo(int& a) { a = 0; } int main() { std::function f = &foo; std::cout << (size_t)&foo << std::endl << getAddress(f) << std::endl; return 0; }
Astuce: lorsque vous avez des problèmes avec la syntaxe C ++, je vous suggère d'utiliser clang++
pour comstackr votre code. Si vous jouez avec la façon dont vous écrivez le code, cela vous indiquera généralement la direction à suivre pour corriger l'erreur (quand il pourra comprendre ce que vous faites).
Je vous suggère également d'utiliser des modèles variadiques pour rendre votre fonction un peu plus générale:
template size_t getAddress(std::function f) { typedef T(fnType)(U...); fnType ** fnPointer = f.template target(); return (size_t) *fnPointer; }
Un std::function
est juste un object, bien que déguisé en non-un-object. Donc, nous pouvons prendre l’adresse de cet object, et c’est invariant d’une copie à l’autre, etc.
Pour obtenir le pointeur, il nous faut un peu de casting. Par exemple, avec une fonction f1
, nous pouvons imprimer le pointeur implicite en faisant:
std::cout << "f1: " << *(long *)(char *)&f1 << std::endl;
Ce que cela fait est:
long
, nous pouvons le derefernce en long et obtenir l’adresse sous-jacente associée à l’object fonction. Avec deux std::function
s f1
et f2
, nous pouvons faire des choses comme:
std::cout << "f1: " << *(long *)(char *)&f1 << std::endl; std::cout << "f2: " << *(long *)(char *)&f2 << std::endl; std::function f1copy = f1; std::cout << "\nafter copy f1 into f1copy:" << std::endl; std::cout << "addresses of f1 and f1copy differ: " << &f1 << " " << &f1copy << std::endl; std::cout << "but underlying pointers identical: " << *(long *)(char *)&f1 << " " << *(long *)(char *)(&f1copy) << std::endl; std::cout << "\n after assign f2 to f1copy" << std::endl; f1copy = f2; std::cout << "now the underlying pointer of f1copy matches f2's:" << std::endl; std::cout << *(long *)(char *)&f2 << " " << *(long *)(char *)&f1copy << std::endl;
Exemple de sortie:
f1: 4439003784 f2: 4439003912 after copy f1 into f1copy: addresses of f1 and f1copy differ: 0x7fff572ab970 0x7fff572ab910 but underlying pointers identical: 4439003784 4439003784 after assign f2 to f1copy now the underlying pointer of f1copy matches f2's: 4439003912 4439003912