我有一个类模板DataProcessor
,如下所示:
struct DataProcessorBase
{
typedef std::shared_ptr<DataProcessorBase> Ptr;
}; // struct DataProcessorBase
template <class _Input, class _Output>
struct DataProcessor : DataProcessorBase
{
typedef _Input Input;
typedef _Output Output;
virtual Output process(const Input * input) = 0;
}; // struct DataProcessor
我希望创建一个Pipeline类,它将多个DataProcessor
实例连接在一起。这意味着处理器1的输出必须与处理器2的输入匹配,依此类推。如下所示:
template <class _Input, class _Output>
class Pipeline : DataProcessor<_Input, _Output>
{
public:
Output process(const Input * input);
private:
std::vector<DataProcessorBase::Ptr> _processors;
}; // class Pipeline
template <class _Input, class _Output>
_Output Pipeline<_Input, _Output>::process(const _Input * input)
{
// this is where I start guessing...
auto rawPtr = dynamic_cast<DataProcessor<_Input, TYPEOFFIRSTPROCESSORSOUTPUT>*>(_processors[0]);
assert(rawPtr);
for (size_t i = 0; i < _processors.size(); ++i)
{
...
}
}
我可以说这种实现Pipeline :: process的方式不正确。有人能指出我正确的方向吗?
答案 0 :(得分:3)
解除拨入和拨出电话。
数据传入和数据出现应该在不同的步骤发生。然后,每个数据使用者都可以知道它需要什么,并为您进行转换(如果出现问题,可能会抛出或错误标记)。
struct processor {
virtual ~processor () {};
virtual bool can_read_from( processor const& ) const = 0;
virtual void read_from( processor& ) = 0;
virtual bool ready_to_sink() const = 0;
virtual bool ready_to_source() const = 0;
};
template<class T>
struct sink {
virtual void operator()( T&& t ) = 0;
virtual ~sink() {}
};
template<class T>
struct source {
virtual T operator()() = 0;
virtual ~source() {}
};
template<class In, class Out, class F>
struct step: processor, sink<In>, source<Out> {
F f;
step( F&& fin ):f(std::move(fin)) {}
step(step&&)=default;
step(step const&)=default;
step& operator=(step&&)=default;
step& operator=(step const&)=default;
step()=default;
std::experimental::optional<Out> data;
virtual void operator()( In&& t ) final override {
data = f(std::move(t));
}
virtual bool ready_to_sink() const {
return !data;
}
virtual Out operator()() final override {
auto tmp = std::move(data);
data = {};
return std::move(*tmp);
}
virtual bool ready_to_source() const final override {
return static_cast<bool>(data);
}
virtual bool can_read_from( processor const& o ) final override {
return dynamic_cast<source<In> const*>(&o);
}
virtual void read_from( processor &o ) final override {
(*this)( dynamic_cast<source<In>&>(o)() );
}
};
template<class In, class Out>
struct pipe {
std::shared_ptr<processor> first_step;
std::vector< std::shared_ptr<processor> > steps;
pipe(std::shared_ptr<processor> first, std::vector<std::shared_ptr<processor>> rest):
first_step(first), steps(std::move(rest))
{}
Out operator()( In&& in ) {
(*dynamic_cast<sink<In>*>(steps.first_step.get()))( std::move(in) );
auto last = first_step;
for (auto step:steps) {
step->read_from( *last );
last = step;
}
return (*dynamic_cast<source<Out>*>(last.get())();
}
};
template<class In, class Out>
struct pipeline:step<In, Out, pipe<In,Out>> {
pipeline( std::shared_pointer<processor> first, std::vector<std::shared_ptr<processor>> steps ):
step<In, Out, pipe<In,Out>>({ first, std::move(steps) })
{}
};