Question

I am going to use an example with which I am having trouble with, but I will try to keep the topic as generic as possible. I have a function which takes a parameter of type void (*)(), which I want to bind from another function taking input parameters using std::bind. Can this be done? Below is my example from freeglut:

(I had read this: convert std::bind to function pointer, which confirms that the following doesn't work - workarounds???)

void callback(Obj obj1, Obj obj2, Obj obj3)
{
  // do something with the object and display data
}

// meanwhile, in main()
std::function<void ()> callbackFunctor = &std::bind(callback, obj1, obj2, obj3);

// the following doesn't work because glutIdleFunc expects a type void (*)()
glutIdleFunc(callbackFunctor );

Aside from making obj1, obj2 and obj3 globals, how does one normally pass information onto the idle callback in GLUT?

Was it helpful?

Solution

You can't convert a std::function to a function pointer (you can do the opposite).

I was looking around a bit and I found this post on how to store variadic packs.

If you modify that code a bit, making the members static, it might be of use to you:

namespace helper {
    template <std::size_t... Ts>
    struct index {};

    template <std::size_t N, std::size_t... Ts>
    struct gen_seq : gen_seq<N - 1, N - 1, Ts...> {};

    template <std::size_t... Ts>
    struct gen_seq<0, Ts...> : index<Ts...> {};
}

template <typename... Ts>
class Action {
private:
    static std::function<void (Ts...)> f_;
    static std::tuple<Ts...> args_;
public:
    template <typename F, typename... Args>
    static void setAction(F&& func, Args&&... args) {
        f_ = std::forward<F>(func);
        args_ = std::make_tuple(std::forward<Args>(args)...);
    }

    template <typename... Args, std::size_t... Is>
    static void func(std::tuple<Args...>& tup, helper::index<Is...>) {
        f_(std::get<Is>(tup)...);
    }

    template <typename... Args>
    static void func(std::tuple<Args...>& tup) {
        func(tup, helper::gen_seq<sizeof...(Args)>{});
    }

    static void act() {
        func(args_);
    }
};

// Init static members.
template <typename... Ts> std::function<void (Ts...)> Action<Ts...>::f_;
template <typename... Ts> std::tuple<Ts...> Action<Ts...>::args_;

Using the code above you can store any function or function object with arbitrary parameters specified at runtime as an Action and use its static member function act(), which takes no parameters, to call the stored function with the previously specified parameters.

As act() is convertible to void (*)() it can be passed to you callback function.

The following should work:

auto someCallable = [] (int x) { std::cout << "Number " << x << std::endl };
Action<int>::setAction(someCallable, 1); // Pass func and parameters.
glutIdleFunc(Action<int>::act);

OTHER TIPS

Globals (better static ones, visible only to one file), possibly chained into folded function call, or separate system with e.g. set_/get_userdata(function_address) call within callee function.

The question is, if your callback is called always with the same parameters, why do you want to pass them this way? GLUT API don't have this because it just have no use.

In any way, no API could cover all of your possible requests. If something doesn't fits, you have to rethink what are you doing and, if you sure, implement your own workaround on top of given API.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top