如何将元组提取到函数参数中

How to extract tuple into a function parameters

我在 Linux 上使用 C++,我需要开发一个通用库来简化多线程开发。

嗯,我知道C++11中有一些多线程机制,比如std::asyncstd::future等。但是我必须使用pthread由于一些历史原因。

基本上,我想做的是制作一个非常非常简单的模板函数,有点像 std::future。在这里。

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;
}

一句话,我尝试把函数的参数包装成元组,把元组传入pthread_create的第三个参数,也就是一个labmda

所以在这段代码中,std::get<0>(*param)是函数,元组的其余部分*param是应该传递给函数的参数列表。但我不知道如何扩展它。显然,std::get<0>(*param)(std::get<1>(*param)); 是不行的,因为它只能处理一个参数的函数。如果我想传递一个有两个参数的函数,我会得到一个错误。

那么如何展开那里的元组呢?

顺便说一句,请忽略其他问题,例如为什么不调用pthread_join。我只是在这里删除它们以最小化我的 post.

如评论中所述,std::apply适合您的情况。

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.

如果你不能使用 C++17 (std::apply()),我想你必须添加一个间接级别...

您的 func() 可以调用 func2()

template<typename F, typename... Args>
void func(F* f, Args&&... args) {
    func2(std::make_index_sequence<sizeof...(Args)>{}, f,
          std::forward<Args>(args)...);
}

它还接收一个索引模板序列,所以你的 lambda,现在在 func2() 中(我已经删除了 pthread 部分......对不起)可以写成如下

template <std::size_t ... Is, typename F, typename ... Args>
void func2 (std::index_sequence<Is...>, F * f, Args && ... args) {
    typename signature<decltype(f)>::argument_type tp = std::make_tuple(f, std::forward<Args>(args)...);
    [](void *p){
      auto param = static_cast<typename signature<decltype(f)>::argument_type*>(p);
      std::get<0>(*param)(std::get<1u+Is>(*param)...);
      return (void*)nullptr; }(&tp);
}