Obtenga el puntero de función de std :: function cuando usa std :: bind

Estoy tratando de usar std::function junto con std::bind , pero estoy teniendo algunos problemas.

Esto funciona:

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

Esto se bloquea en la segunda línea de main :

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

Realmente estoy sosteniendo la std::function y necesito poder devolver la función; no solo llámalo. Espero que el uso sea algo como esto:

 #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 */ } 

¿Hay alguna forma de recuperar la función original o una alternativa? También entra en conflicto con el tipo de devolución, ya que void (*)() coincide bastante bien con la firma enlazada.

Esto es completamente imposible. Toda la razón por la que std::function existe es que los punteros de función chupan horriblemente y nunca deben ser utilizados por nadie, nunca más, excepto por las almas condenadas que llevan la interoperación Burning Standards of Hell C, porque no pueden manejar funciones con estado .

Una std::function no puede, en el caso general, convertirse en un void(*)() . La única razón por la que esto funciona en el primer ejemplo es porque pasa a ser un void(*)() originalmente.

Esto se puede lograr usando una pequeña meta-progtwigción de plantillas. Recientemente tuve uso para esto mientras escribía un contenedor genérico de C ++ alrededor de OpenGL GLUT (que depende de los punteros de función de callback). El enfoque:

  1. Crear una instancia de un tipo de plantilla singleton.
  2. Almacene su función std :: como miembro de la instancia singleton
  3. Invoque su función std :: a través de una función miembro estática (las funciones miembro estáticas y las funciones gratuitas tienen el mismo tipo, por lo que la función “invocar” puede usarse como un puntero de función libre)

Probado bajo C ++ 11 en 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))< 

No puede obtener un puntero de función de una función std::function , ya que puede que ni siquiera haya una. Podría ser un puntero de función miembro en su lugar, o un objeto que implementa operator() .