Reputation: 12371
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.
Upvotes: 0
Views: 1895
Reputation: 66200
If you can't use C++17 (std::apply()
), I suppose you have to add a level of indirection...
Your func()
can call a func2()
template<typename F, typename... Args>
void func(F* f, Args&&... args) {
func2(std::make_index_sequence<sizeof...(Args)>{}, f,
std::forward<Args>(args)...);
}
that receive also a template sequence of indexes, so your lambda, now inside func2()
(I've removed the pthread part... sorry) can be written as follows
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);
}
Upvotes: 1
Reputation: 42776
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);
Upvotes: 3