2017-09-23 6 views
1

J'essaie d'implémenter un modèle composite pour std::functions en utilisant des classes de modèle, où chaque classe composite traite les valeurs de retour de ses enfants.
Ainsi, les classes de modèle pourrait ressembler à ceci:Modèle composite de std :: fonctions

class AbstractClass { 
    public: 
    virtual void process() = 0; 
}; 

template<typename ReturnType> 
class PrimitiveClass : public AbstractClass { 
    public: 
    ReturnType process() { 
     // please note, that the result is not returned by the return statement 
     return this->func(); //this is just for simplicity 
    } 

    private: 
    std::function<ReturnType()> func; 
} 

template<typename ReturnType, typename ...Args> 
class CompositeClass : public AbstractClass { 
    public: 
    ReturnType process() { 
     // --> This is where I want to process all children first and then pass their return values to this->func 
     // the following code is kind of a pseudo code: 
     for(auto it = vector.begin(); it != vector.end(); ++it { 
      results.add((**it).process()) 
     } 
     return this->func(results) 
    } 

    private: 
    std::function<ReturnType(Args...)> func; 
    std::vector<std::shared_ptr<AbstractClass>> children; 
}; 

Ainsi, par exemple, j'ai un CompositeClass avec un std::function<int(int, double, bool) et les types d'arguments de cette fonction sont également les ReturnType s de ses enfants. Et je veux passer les valeurs de retour des enfants à ci-dessus std::function
Quelqu'un peut-il penser à un moyen, comment je peux y parvenir?

+0

"le résultat n'est pas retourné par l'instruction return"? Quelle? – melpomene

+0

Mais quel problème avec le passage des résultats comme std :: vecteur au lieu de Args ...? –

+0

@ArtemyVysotsky car les enfants peuvent avoir des types de retour différents @melpomene 'process' est une fonction virtuelle pure avec le type de retour void, alors que ce n'est pas le cas dans les classes dérivées. Dans cet exemple, la fonction 'process' des classes dervies a un type et une valeur de retour, pour rendre les choses plus claires –

Répondre

2

Si je comprends ce que vous voulez (et si je ne me trompe pas) ...

(1) pour résoudre le problème de la valeur renvoyée sans covariante de process() (voir le commentaire de Igor Tandetnik) vous besoin d'une classe abstraite modèle pour exprimer la valeur de retour correcte; par exemple

template <typename T> 
struct abstClass 
{ virtual T process() const = 0; }; 

(2) de sorte que votre CompositeClass (renommé nodeClass, dans mon exemple suivant) hériter de abstClass<ReturnType>

(3) votre PrimitiveClass est inutile parce que vous pouvez gérer le cas (référence à une fonction sans arguments) comme CompositeClass avec zéro Args

(4) vous avez besoin d'un leafClass pour gérer les valeurs de base

(5) CompositeClass (nodeClass), children, au lieu d'un std::vector de shared_ptr<AbstractClass> (qui ne peut pas faire ce que vous voulez), peut être, je propose

std::tuple<std::shared_ptr<abstClass<Args>>...> children; 

Compte tenu de ces points, la solution suivante (cela, malheureusement, est C++ 14 car utiliser std::index_sequence et std::make_index_sequence qui sont disponibles à partir de C++ 14; mais si vous avez besoin d'une solution C++ 11, n'est pas difficile de les remplacer par l'écriture)

#include <tuple> 
#include <memory> 
#include <iostream> 
#include <functional> 

template <typename T> 
struct abstClass 
{ virtual T process() const = 0; }; 

template <typename T> 
class leafClass : public abstClass<T> 
{ 
    private: 
     T value; 

    public: 
     leafClass (T && v0) : value { std::forward<T>(v0) } 
     { } 

     T process() const 
     { return value; }; 
}; 

template <typename RetT, typename ... ArgTs> 
class nodeClass : public abstClass<RetT> 
{ 
    private: 
     using funcT = std::function<RetT(ArgTs...)>; 

     template <typename T> 
     using shrPAC = std::shared_ptr<abstClass<T>>; 

     funcT       func; 
     std::tuple<shrPAC<ArgTs>...> childrens; 

     template <std::size_t ... Is> 
     RetT processH (std::index_sequence<Is...> const &) const 
     { return func(std::get<Is>(childrens)->process()...); } 

    public: 
     nodeClass (funcT && f0, shrPAC<ArgTs> && ... as) 
     : func { std::forward<funcT>(f0) }, 
      childrens { std::forward<shrPAC<ArgTs>>(as)... } 
     { } 

     RetT process() const 
     { return processH(std::make_index_sequence<sizeof...(ArgTs)>{}); } 
}; 

int main() 
{ 
    auto func0 = [](int i, double d, bool b) { return int(b ? i+d : i-d); }; 

    auto shpLci = std::make_shared<leafClass<int>>(1); 
    auto shpLcd = std::make_shared<leafClass<double>>(2.2); 

    auto shpNb = std::make_shared<nodeClass<bool>>([](){ return true; }); 

    auto shpNc0 = std::make_shared<nodeClass<int, int, double, bool>> 
     (func0, shpLci, shpLcd, shpNb); 
    auto shpNc1 = std::make_shared<nodeClass<int, int, double, bool>> 
     (func0, shpNc0, shpLcd, shpNb); 
    auto shpNc2 = std::make_shared<nodeClass<int, int, double, bool>> 
     (func0, shpNc1, shpLcd, shpNb); 

    std::cout << shpNc0->process() << std::endl; // print 3 
    std::cout << shpNc1->process() << std::endl; // print 5 
    std::cout << shpNc2->process() << std::endl; // print 7 
} 
+0

Ceci et Artemy Vysotskys réponse aide beaucoup. Je pense que je peux et vais le faire de cette façon. Merci beaucoup pour ton effort! –