2017-09-03 2 views
2

Je souhaite lier tout type d'événement à des fonctions de tout type pour le système d'interface utilisateur (G) d'un jeu sur lequel je travaille. Je souhaite stocker n'importe quel type de fonctions et ses arguments initiaux dans une classe de modèle Functor, que je peux lier à un index de liaison de signal. Les événements liés à une liaison de signal le déclenchent dès qu'ils apparaissent dans la file d'attente d'événements, ce qui provoque l'appel de tous les Functors liés à cette liaison.Implémentation d'un modèle Functor pouvant stocker les arguments de sa fonction

J'ai trouvé que le moyen de stocker les arguments de la fonction était d'utiliser un std::tuple dans le modèle de foncteur, mais j'ai besoin d'aide pour l'initialiser correctement et le déballer correctement lors de l'appel de la fonction.

C'est ce que j'ai jusqu'à présent:

template<typename R, typename... Args> 
class FuncBinding { 
private: 
    std::tuple<Args...> args; 
    R(*fun)(Args...); 

public:    
    FuncBinding(R(*pF)(Args...) , Args... pArgs) 
     :fun(pF), args(std::make_tuple<Args...>(pArgs)) {} 

    R invoke() { 
     return fun(args...); 
    } 

    R callFunc(Args... pArgs) { 
     return fun(pArgs...); 
    } 
}; 

Comment puis-je utiliser le pack de paramètres Args correctement pour ...

  • ... créer la classe de modèle std::tuple<Args...> appropiately
  • ... initialise le std::tuple<Args...> instance args avec les arguments de foncteur
  • ... déballer e tuple lorsque vous appelez la fonction via le pointeur de fonction R(*fun)(Args...)
+0

possible [dupe] (https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer/20441189#20441189). – Walter

Répondre

3

Un tuple est juste un autre type de classe du point de vue de l'initialisation, de sorte que vous initialisez juste en passant le paquet dans son constructeur:

FuncBinding(R(*pF)(Args...) , Args... pArgs) 
: fun(pF), args(pArgs...) 
{ } 

ou, de manière plus efficace:

args(std::forward<Args>(pArgs)...) 

J'utilise forward au lieu de std::move() au cas où certains Args... sont des types de référence lvalue. Du côté de l'invocation


, il y a une fonction 17 C++ appelé std::apply() qui fait ce que vous voulez:

R invoke() { 
    return std::apply(fun, args); 
} 

Il est implémentable en C++ 11. La page cppreference contient une implémentation qui implique std::make_index_sequence, elle-même implémentable dans C++ 11 (et il existe de nombreuses implémentations de ce type sur ce site).

+0

merci. Je suppose que l'utilisation de la solution C++ 17 ('std :: apply') est généralement préférée? – stimulate

+0

@stimulate Si vous utilisez un compilateur C++ 17, alors oui, utilisez 'std :: apply()' directement - il est déjà écrit pour vous. Si non, alors vous devrez l'implémenter vous-même - mais ce n'est pas difficile à faire. – Barry

+1

Pour ceux qui sont intéressés, une implémentation possible de C++ 11 'index_sequence' est ici: https://stackoverflow.com/a/24481400/1944004 –