C ++ essayant d’obtenir l’adresse d’une fonction std :: function

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:

  • prend l'adresse de f1. f1 est lui-même un pointeur sur l'object fonction, bien que déguisé en primitive
    • donc cette adresse est un pointeur sur le pointeur sur la fonction
    • ce que nous voulons, c'est le pointeur sous-jacent à la fonction
  • jette le pointeur à pointeur dans un pointeur sur char
  • de là à un pointeur à long
  • maintenant, en supposant que les tailles de pointeur sont 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