Récupère le pointeur de fonction de std :: function lors de l’utilisation de std :: bind

J’essaie d’utiliser std::function en conjonction avec std::bind , mais j’ai des problèmes.

Cela marche:

 #include  #include  void print() { std::cout << 2; } int main() { std::function foo = print; (*foo.target())(); //prints 3 } 

Cela se bloque à la deuxième ligne de main :

 #include  #include  void print (int i) { std::cout << i; } int main() { std::function foo = std::bind (print, 2); (*foo.target())(); } 

Je tiens vraiment le std::function et ai besoin de pouvoir retourner la fonction; pas juste l’appeler. Je m’attends à ce que l’utilisation ressemble à ceci:

 #include  #include  void print (int i) { std::cout << i; } int main() { Container c (std::bind (print, 2)); //I would expect the original c.func() (3); //prints 3 if (c.func() == print) /* this is what I'm mostly getting at */ } 

Existe-t-il un moyen de renvoyer la fonction d’origine ou une alternative? Il y a aussi une sorte de conflit avec le type de retour, puisque void (*)() correspond assez bien à la signature liée.

C’est tout à fait impossible. La raison pour laquelle std::function existe est que les pointeurs de fonction sucent horriblement et ne devraient jamais, plus jamais être utilisés par qui que ce soit, à l’exception des âmes maudites portant l’ interopération Burning Standards of Hell C, car elles ne peuvent pas gérer les fonctions avec .

Un std::function ne peut pas, dans le cas général, être converti en void(*)() . La seule raison pour laquelle cela fonctionne dans le premier exemple est qu’il s’agit à l’origine d’un void(*)() .

Ceci peut être réalisé en utilisant un petit modèle de méta-programmation. J’avais récemment utilisé pour cela tout en écrivant un wrapper C ++ générique autour de OpenGL GLUT (qui dépend des pointeurs de fonction de rappel). L’approche:

  1. Instanciez une instance d’un type de modèle singleton.
  2. Stocke votre std :: function en tant que membre de l’instance singleton
  3. Appelez votre fonction std :: via une fonction membre statique (les fonctions membres statiques et les fonctions libres ont le même type, de sorte que la fonction “invoke” peut être utilisée comme pointeur de fonction libre)

Testé sous C ++ 11 sur GCC 4.8 .

 #include  #include  #include  #include  #include  #include  #include  template  struct fun_ptr_helper { public: typedef std::function<_Res(_ArgTypes...)> function_type; static void bind(function_type&& f) { instance().fn_.swap(f); } static void bind(const function_type& f) { instance().fn_=f; } static _Res invoke(_ArgTypes... args) { return instance().fn_(args...); } typedef decltype(&fun_ptr_helper::invoke) pointer_type; static pointer_type ptr() { return &invoke; } private: static fun_ptr_helper& instance() { static fun_ptr_helper inst_; return inst_; } fun_ptr_helper() {} function_type fn_; }; template  typename fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::pointer_type get_fn_ptr(const std::function<_Res(_ArgTypes...)>& f) { fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::bind(f); return fun_ptr_helper<_UniqueId, _Res, _ArgTypes...>::ptr(); } template std::function::value, T>::type> make_function(T *t) { return {t}; } int main() { std::cout << (void*)get_fn_ptr<0>(make_function(::sin))< 

Vous ne pouvez pas obtenir un pointeur de fonction à partir d’un std::function , car il se peut même qu’il n’en existe pas. Ce pourrait être un pointeur de fonction membre ou un object qui implémente operator() .