如何将元组提取到函数参数中
How to extract tuple into a function parameters
我在 Linux 上使用 C++,我需要开发一个通用库来简化多线程开发。
嗯,我知道C++11中有一些多线程机制,比如std::async
、std::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);
如果你不能使用 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);
}
我在 Linux 上使用 C++,我需要开发一个通用库来简化多线程开发。
嗯,我知道C++11中有一些多线程机制,比如std::async
、std::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);
如果你不能使用 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);
}