传递元组的内容作为可变函数参数 [英] Pass tuple's content as variadic function arguments

查看:287
本文介绍了传递元组的内容作为可变函数参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我玩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 with std::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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆