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?
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);