Search code examples
c++templatestuplesc++14template-meta-programming

How to extract tuple into a function parameters


I'm working with C++ on Linux and I need to develop a common library to simplify the multi-threading development.

Well, I know that there are some mechanism of multi-threading in C++11, such as std::async, std::future etc. But I have to work with pthread because of some historical reason.

Basically, what I'm trying to do is to make a very very simple template function, which is kind of like std::future. Here it is.

template<typename S>
struct signature;

template<typename R, typename... Args>
struct signature<R(*)(Args...)> {
    using return_type = R;
    using argument_type = std::tuple<R(*)(Args...), Args...>; // f, args...
};

template<typename F, typename... Args>
void func(F* f, Args&&... args) {
    typename signature<decltype(f)>::argument_type tp = std::make_tuple(f, std::forward<Args>(args)...);
    pthread_t td;
    pthread_create(&td, nullptr, [](void *p){
            auto param = static_cast<typename signature<decltype(f)>::argument_type*>(p);
            std::get<0>(*param)(std::get<1>(*param)); // ???
            return (void*)nullptr;
            }, &tp);
}

void f(int a) {}
void f2(int a, int b) {}

int main() {
    func(f, 1);
    // func(f2, 2, 2); ERROR!

    return 0;
}

In a word, I try to wrap the parameters of the function into a tuple and pass the tuple into the third parameter of pthread_create, which is a labmda.

So in the piece of code, std::get<0>(*param) is the function, and the rest part of the tuple *param is the parameter list which should be passed to the function. But I don't know how to expand it. Obvisouly, std::get<0>(*param)(std::get<1>(*param)); is not OK because it can only handle the function with one parameter. If I want to pass a function with two parameters, I will get an error.

So how to expand the tuple there?

BTW, please ignore other issues, such as why don't call pthread_join. I just remove them here to minimize my post.


Solution

  • As mentioned in the comments, std::apply is suitable for your case.

    pthread_create(
      &td, nullptr,
      [](void* p) {
        auto param = static_cast<typename signature<decltype(f)>::argument_type*>(p);
        std::apply([](auto& f, auto&&... args) { 
          f(std::forward<decltype(args)>(args)...); 
        }, *param);
        return (void*)nullptr;
      },
      &tp);
    

    Demo.