Get function pointer from std::function when using std::bind
I'm trying to use std::function
in conjunction with std::bind
, but I'm having some problems.
This works:
#include <functional>
#include <iostream>
void print() {
std::cout << 2;
}
int main() {
std::function<void ()> foo = print;
(*foo.target<void (*)()>())(); //prints 3
}
This crashes at the second line of main
:
#include <functional>
#include <iostream>
void print (int i) {
std::cout << i;
}
int main() {
std::function<void ()> foo = std::bind (print, 2);
(*foo.target<void (*)()>())();
}
I'm really holding the std::function<void ()>
and need to be able to return the function; not just call it. I expect the usage would be something like this:
#include <functional>
#include <iostream>
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 */
}
Is there any way to get the original function to return it, or an alternative? It does kind of conflict with the return type as well, as void (*)()
matches the bound signature quite nicely.
Solution 1:
This is quite impossible. The whole reason that std::function
exists is that function pointers suck horrifically and should never, ever, be used by anyone, ever again, except for the doomed souls bearing the Burning Standards of Hell C interoperation, because they cannot handle functions with state.
A std::function<void()>
cannot, in the general case, be converted to a void(*)()
. The only reason this works in the first example is because it happens to be a void(*)()
originally.
Solution 2:
This can be achieved using a little template meta-programming. I recently had use for this while writing a generic C++ wrapper around OpenGL GLUT (which depends on callback function pointers). The approach:
- Instantiate an instance of a singleton template type.
- Store your std::function as a member of to the singleton instance
- Invoke your std::function through a static member function (static member functions and free functions have the same type, so the "invoke" function can be used as a free function pointer)
Tested under C++11 on GCC 4.8.
#include <unistd.h>
#include <thread>
#include <chrono>
#include <mutex>
#include <functional>
#include <iostream>
#include <cmath>
template <const size_t _UniqueId, typename _Res, typename... _ArgTypes>
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 <const size_t _UniqueId, typename _Res, typename... _ArgTypes>
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<typename T>
std::function<typename std::enable_if<std::is_function<T>::value, T>::type>
make_function(T *t)
{
return {t};
}
int main()
{
std::cout << (void*)get_fn_ptr<0>(make_function(::sin))<<std::endl;
return 0;
}