std :: functions的复合模式

问题描述:

我想用std::functions模板类来实现一个复合模式,其中每个复合类都处理其子元素的返回值。
所以图案类可能是这个样子:std :: functions的复合模式

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

因此,举例来说,我有一个std::function<int(int, double, bool)和参数类型的函数的CompositeClass也是ReturnType开发它的孩子。我想通过孩子的返回值到上述std::function
任何人都可以想出一个办法,我怎么能做到这一点?

+0

“的结果不是由return语句返回”?什么? – melpomene

+0

但是将结果作为std :: vector 而不是Args ...传递给结果有什么问题? –

+0

@ArtemyVysotsky因为孩子可能有不同的返回类型 @melpomene'process'是一个返回类型为void的纯虚函数,而在派生类中则不是。在这个例子中dervied类'process'功能有返回类型和价值,让事情更清晰 –

如果我知道你想什么(如果我没看错)...

(1)从解决process()(请参阅从伊戈尔Tandetnik评论)你无协变返回值的问题需要一个模板抽象类来表示正确的返回值;举例

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

(2)让你的CompositeClass(改名nodeClass,我在下面的例子中)从abstClass<ReturnType>继承

(3)你的PrimitiveClass是无用的,因为你可以管理的情况下(参照功能而不参数)作为CompositeClassArgs

(4),你需要一个leafClass处理基本价值观

(5)CompositeClassnodeClass),children,而不是一个shared_ptr<AbstractClass>std::vector(不能做你想要什么),可以是

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

鉴于这些问题,笔者提出以下解决方案(不幸的是,C++ 14是因为使用从C++ 14开始可用的std::index_sequencestd::make_index_sequence;但如果你需要一个C++ 11的解决方案,是不是因为他们很难写替代品)

#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

这和Artemy Vysotskys的回答有很大的帮助。我想我可以并且会这样做。非常感谢你的努力! –