std::functions 的复合模式
Composite pattern of std::functions
我正在尝试使用模板 classes 为 std::functions
实现复合模式,其中每个复合 class 处理其 children.
所以模式 classes 可能看起来像这样:
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;
};
例如,我有一个 CompositeClass
和一个 std::function<int(int, double, bool)
,并且该函数的参数类型也是其 children 的 ReturnType
。我想将 children 的 return 值传递给 above-mentioned std::function
谁能想出办法,我怎么能做到这一点?
如果我明白你想要什么(如果我没有错的话)...
(1) 要解决 process()
的非协变 returned 值的问题(请参阅 Igor Tandetnik 的评论),您需要一个模板摘要 class 来表达正确的 return 值;举个例子
template <typename T>
struct abstClass
{ virtual T process() const = 0; };
(2) 因此您的 CompositeClass
(在我的以下示例中重命名为 nodeClass
)继承自 abstClass<ReturnType>
(3) 您的 PrimitiveClass
没用,因为您可以将大小写(对不带参数的函数的引用)管理为零 Args
的 CompositeClass
(4) 你需要一个 leafClass
来处理基本值
(5) in CompositeClass
(nodeClass
), children
, 而不是 shared_ptr<AbstractClass>
的 std::vector
(那不能做什么你想要的),可以是
std::tuple<std::shared_ptr<abstClass<Args>>...> children;
鉴于这些要点,我提出以下解决方案(不幸的是,这是 C++14,因为使用从 C++14 开始可用的 std::index_sequence
和 std::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
}
我正在尝试使用模板 classes 为 std::functions
实现复合模式,其中每个复合 class 处理其 children.
所以模式 classes 可能看起来像这样:
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;
};
例如,我有一个 CompositeClass
和一个 std::function<int(int, double, bool)
,并且该函数的参数类型也是其 children 的 ReturnType
。我想将 children 的 return 值传递给 above-mentioned std::function
谁能想出办法,我怎么能做到这一点?
如果我明白你想要什么(如果我没有错的话)...
(1) 要解决 process()
的非协变 returned 值的问题(请参阅 Igor Tandetnik 的评论),您需要一个模板摘要 class 来表达正确的 return 值;举个例子
template <typename T>
struct abstClass
{ virtual T process() const = 0; };
(2) 因此您的 CompositeClass
(在我的以下示例中重命名为 nodeClass
)继承自 abstClass<ReturnType>
(3) 您的 PrimitiveClass
没用,因为您可以将大小写(对不带参数的函数的引用)管理为零 Args
CompositeClass
(4) 你需要一个 leafClass
来处理基本值
(5) in CompositeClass
(nodeClass
), children
, 而不是 shared_ptr<AbstractClass>
的 std::vector
(那不能做什么你想要的),可以是
std::tuple<std::shared_ptr<abstClass<Args>>...> children;
鉴于这些要点,我提出以下解决方案(不幸的是,这是 C++14,因为使用从 C++14 开始可用的 std::index_sequence
和 std::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
}