How can I pass a parameter pack to a void pointer in C++?

124 Views Asked by At

Please consider the following code example:

#include <functional>
#include <iostream>

template <typename... Ts>
class SomeClass
{
public:
    std::function<bool(Ts...)> some_func;

    void run(Ts... args)
    {
        this->some_func(args...); // this works

        this->thread_run((void *)&this->some_func, args); // this won't work, can't pass the parameter pack
    }

    static void thread_run(void *func_ptr, void *args_ptr)
    {
        auto thread_func = *(std::function<bool(Ts...)> *)(func_ptr);
        thread_func(2, 3);
    }
};

int main()
{
    SomeClass<int, int> a;

    a.some_func = [](int x, int y)
    { std::cout << "Arguments: " << x << " " << y << std::endl; return x > y; };

    a.run(2, 3);

    return 0;
}

As you can see, there is a class that has a template std::function member variable. I can set it by giving it a lambda expression that must return bool but can have any number of arguments, which is nice!

Sadly, I am now given the task to run this function as a thread with a given threading library (which is non-negotiable). The entry function for the threading library has to be a static function with the following signature:

void (*thread_entry_t)(void *p1, void *p2)

I've managed to pass the std::function variable to the static function in the example, see the thread_run() function, but I can't find a way to pass the parameter pack args to the static function through the void* pointers.

How could I do it?

1

There are 1 best solutions below

1
Caleth On BEST ANSWER

You can wrap args... in a tuple, and pass a pointer to that. I've made it a member of your class so that it has the same lifetime as the std::function object.

template <typename... Ts>
class SomeClass
{
public:
    std::function<bool(Ts...)> some_func;
    std::tuple<Ts...> args;

    void run(Ts... args)
    {
        this->args = { args... };    
        thread_run((void *)&this->some_func, (void *)&this->args);
    }

    static void thread_run(void *func_ptr, void *args_ptr)
    {
        auto & thread_func = *(std::function<bool(Ts...)> *)(func_ptr);
        auto & args = *(std::tuple<Ts...> *)(args_ptr);
        std::apply(thread_func, args);
    }
};