传递元组的内容作为可变函数参数 [英] Pass tuple's content as variadic function arguments
问题描述
我玩C ++ 0x一段时间,现在我想使用可变参数模板和元组来实现类任务。我要将任务对象传递到新创建的线程(使用pthread)。任务类将包含函数的函数指针,该函数应该在线程和函数的参数内调用,简化代码:
class TaskCaller
{
// ...
virtual bool dispatch(void);
};
template< typename ... T_arguments>任务:
public TaskCaller
{
public:
// ...
任务(bool(* function)(T_arguments& ...),
T_arguments ... arguments):
function_arguments_tuple(arguments ...),
function(function)
{
// ...
}
bool dispatch(void)
{
return TupleUnpack< sizeof ...(T_arguments)> :: unpack(this-> function,this-> function_arguments_tuple);
}
private:
std :: tuple< T_arguments& ...> function_arguments_tuple;
bool(* function)(T_arguments ...);
};
和我用来将tuple解包成函数参数的代码:
template< unsigned int i> class TupleUnpack
{
public:
template< typename T_return_type,typename ... T_tuple_arguments,typename ... T_function_arguments>
inline static T_return_type unpack(T_return_type(* function)(T_tuple_arguments& ...),
std :: tuple< T_tuple_arguments ...& arguments_tuple,
T_function_arguments ... function_arguments )
{
return TupleUnpack< i-1> :: unpack(function,arguments_tuple,std :: get< i-1>(arguments_tuple),function_arguments ...);
}
};
模板<> class TupleUnpack< 0>
{
public:
template< typename T_return_type,typename ... T_tuple_arguments,typename ... T_function_arguments>
inline static T_return_type unpack(T_return_type(* function)(T_tuple_arguments& ...),
std :: tuple< T_tuple_arguments ...& arguments_tuple,
T_function_arguments ... function_arguments )
{
return function(function_arguments ...);
}
};
使用案例:
bool task_function(Foo& foo,Bar& bar)
{
// ...
return true;
}
void * thread_function(void * argument)
{
Task * task((Task *)argument);
task-> dispatch();
删除任务;
pthread_exit(0);
}
void function(void)
{
Foo foo(1,2,3);
酒吧(1,2,3);
任务< Foo,Bar> * task = new任务(task_function,std :: move(foo)std :: move(bar));
pthread_t thread_id;
pthread_create(& thread_id,task_function,task);
}
我没有测试这个代码,但它只是和想法。
现在我想知道TupleUnpack类将如何影响最终的代码。根据我的知识,Task :: dispatch函数(编译器解析模板之后)的最终实现将等效于:
template< ... T_arguments> static bool Task< ... T_arguments> :: dispatch(void)
{
return this-> function(std :: get< 0> function_arguments_tuple),std :: get< ; 1>(this-> function_arguments_tuple),...,std :: get< n>(this-> function_arguments_tuple));
}
右键?
此外,元组本身和std :: get()应该在最终代码中消失,并且不提供运行时开销(根据Boost文档)。
也许有更好的方法来解决我的问题...
但是唯一可以确定的方法是使用你使用的编译器进行测试。
注意,你可以使用 std :: function
与 std :: bind
例如:
模板< typename ... T_arguments> class Task:public TaskCaller
{
std :: function< bool(T_arguments& ...)>函子
public:
任务(bool(* func)(T_arguments& ...),T_arguments ... arguments)
:functor(std :: bind(func,arguments ...) )
{}
bool dispatch(){
return functor();
}
// ...
传递 std :: function
:
class任务:public TaskCaller {
std :: function< bool()>函子
public:
任务(std :: function< bool()> func):functor(func){}
// ...
这允许用户选择传递什么,而不是强制他使用自由函数或静态成员函数。
I play with C++0x for some time and now I want to use variadic templates and tuple to implement class "Task". I'm going to pass Task objects into newly created threads (using pthread). Task class will contain function pointer to function which should be called inside thread and arguments for this function, simplified code:
class TaskCaller { // ... virtual bool dispatch (void); }; template<typename ...T_arguments> Task : public TaskCaller { public: // ... Task (bool (*function) (T_arguments&...), T_arguments... arguments) : function_arguments_tuple (arguments...), function (function) { // ... } bool dispatch (void) { return TupleUnpack<sizeof ...(T_arguments)>::unpack (this->function, this->function_arguments_tuple); } private: std::tuple<T_arguments&...> function_arguments_tuple; bool (*function) (T_arguments...); };
And code which I use to unpack tuple into function arguments:
template<unsigned int i> class TupleUnpack { public: template<typename T_return_type, typename ...T_tuple_arguments, typename ...T_function_arguments> inline static T_return_type unpack (T_return_type (*function) (T_tuple_arguments&...), std::tuple<T_tuple_arguments...>& arguments_tuple, T_function_arguments ...function_arguments) { return TupleUnpack<i-1>::unpack (function, arguments_tuple, std::get<i-1> (arguments_tuple), function_arguments...); } }; template<> class TupleUnpack<0> { public: template<typename T_return_type, typename ...T_tuple_arguments, typename ...T_function_arguments> inline static T_return_type unpack (T_return_type (*function) (T_tuple_arguments&...), std::tuple<T_tuple_arguments...>& arguments_tuple, T_function_arguments ...function_arguments) { return function (function_arguments...); } };
Use case:
bool task_function (Foo &foo, Bar &bar) { // ... return true; } void* thread_function (void* argument) { Task* task ((Task*) argument); task->dispatch (); delete task; pthread_exit (0); } void function (void) { Foo foo (1, 2, 3); Bar bar (1, 2, 3); Task<Foo, Bar>* task = new Task (task_function, std::move (foo) std::move (bar)); pthread_t thread_id; pthread_create (&thread_id, task_function, task); }
I have not tested this code yet it's only and idea.
Now I'm wondering how TupleUnpack class will impact the final code. According to my knowledge final implementation of Task::dispatch function (after compiler parse templates) will be equivalent of:
template<typename ...T_arguments> static bool Task<...T_arguments>::dispatch (void) { return this->function (std::get<0> (this->function_arguments_tuple), std::get<1> (this->function_arguments_tuple), ..., std::get<n> (this->function_arguments_tuple)); }
right?
Moreover tuple itself and std::get() should "disappear" in final code and provide no run-time overhead (according to Boost documentation).
Maybe there's better way to solve my problem...
解决方案It should be equivalent, but the only way to be sure is to test with the compiler you are using.
Note that you could use
std::function
withstd::bind
instead, e.g. something like:template<typename ...T_arguments> class Task : public TaskCaller { std::function<bool (T_arguments&...)> functor; public: Task (bool (*func)(T_arguments&...), T_arguments... arguments) : functor(std::bind(func, arguments...)) {} bool dispatch() { return functor(); } // ...
Or better yet, let the user pass a
std::function
in:class Task : public TaskCaller { std::function<bool ()> functor; public: Task(std::function<bool ()> func) : functor(func) {} // ...
That allows the user to choose what to pass instead of forcing him to use free functions or static member functions.
这篇关于传递元组的内容作为可变函数参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!