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:
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()
.