2010-11-05 13 views
0

Je joue avec C++ 0x depuis un certain temps et maintenant je veux utiliser des templates et des tuple variadiques pour implémenter la classe "Task". Je vais passer des objets Task dans des threads nouvellement créés (en utilisant pthread). classe Task contiendra pointeur de fonction à l'autre qui devrait être appelé à l'intérieur du fil et des arguments pour cette fonction, le code simplifié:Passage du contenu du tuple en tant qu'arguments de la fonction variadique

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...); 
}; 

et le code que j'utilise pour décompresser tuple dans les arguments de la fonction:

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...); 
      }   
}; 

utilisation 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); 
} 

Je n'ai pas encore testé ce code, c'est seulement une idée.

Maintenant, je me demande comment la classe TupleUnpack aura un impact sur le code final. Selon ma connaissance mise en œuvre finale de la fonction Tâche :: dispatch (après modèles parse du compilateur) sera équivalent de:

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)); 
} 

droit?

De plus le tuple lui-même et std :: get() devraient "disparaître" dans le code final et ne fournir aucun temps d'exécution (according to Boost documentation).

Peut-être qu'il ya une meilleure façon de résoudre mon problème ...

Répondre

3

Il devrait équivalent, mais la seule façon d'être sûr est de tester avec le compilateur que vous utilisez.

Notez que vous pouvez utiliser std::function avec std::bind à la place, par ex. quelque chose comme:

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(); 
    } 
    // ... 

Ou mieux encore, que l'utilisateur puisse passer un std::function dans:

class Task : public TaskCaller { 
    std::function<bool()> functor; 
public: 
    Task(std::function<bool()> func) : functor(func) {} 
    // ... 

Cela permet à l'utilisateur de choisir ce qu'il faut passer au lieu de le forcer à utiliser des fonctions libres ou fonctions membres statiques .