Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 612
chris Avatar asked Jun 07 '12 19:06

chris


People also ask

Can we bind function to a pointer?

Yes, bind does it the way you want. You would just bind all the parameters to the function, then you can call it with no arguments.

Is std :: function a function pointer?

No. One is a function pointer; the other is an object that serves as a wrapper around a function pointer. They pretty much represent the same thing, but std::function is far more powerful, allowing you to do make bindings and whatnot.

What is the use of std :: bind?

std::bind. std::bind is a Standard Function Objects that acts as a Functional Adaptor i.e. it takes a function as input and returns a new function Object as an output with with one or more of the arguments of passed function bound or rearranged.

How do you call a function from a pointer?

The call by pointer method of passing arguments to a function copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. This means that changes made to the parameter affect the passed argument.


3 Answers

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.

like image 178
Puppy Avatar answered Oct 26 '22 17:10

Puppy


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:

  1. Instantiate an instance of a singleton template type.
  2. Store your std::function as a member of to the singleton instance
  3. 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;
}
like image 41
fredbaba Avatar answered Oct 26 '22 18:10

fredbaba


You can't get a function pointer out of an std::function, as there may not even be one. It could be a member function pointer instead, or an object that implements operator().

like image 29
K-ballo Avatar answered Oct 26 '22 17:10

K-ballo