【问题标题】:How to extract tuple into a function parameters如何将元组提取到函数参数中
【发布时间】:2022-01-11 11:27:24
【问题描述】:

我在 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&lt;0&gt;(*param) 是函数,元组*param 的其余部分是应该传递给函数的参数列表。但我不知道如何扩展它。很明显,std::get&lt;0&gt;(*param)(std::get&lt;1&gt;(*param)); 不行,因为它只能处理带有一个参数的函数。如果我想传递一个带有两个参数的函数,我会得到一个错误。

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

顺便说一句,请忽略其他问题,例如为什么不打电话给pthread_join。我只是在这里删除它们以最小化我的帖子。

【问题讨论】:

  • 您在寻找std::apply吗?顺便说一句,为什么要使用 pthreads 而不是 C++ 线程?
  • @Daniel Langr 甚至 C++20 std::jthread 加入其析构函数。
  • @DanielLangr 哦,你是对的,我正在寻找它。为什么不使用std::thread?大声笑,那是因为在我的项目中,我既不使用std::thread 也不使用pthread,这是pthread 类似的旧东西......由于某些历史原因,我无权更改它......我的公司开发了它自己的线程,其中包含许多指标的东西。

标签: c++ templates tuples c++14 template-meta-programming


【解决方案1】:

如 cmets 中所述,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++14,所以现在我正在寻找使用 C++14 的 std::apply 的实现......哈哈
【解决方案2】:

如果你不能使用 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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    • 2015-05-11
    • 2011-07-04
    • 1970-01-01
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多