管道 class 存储具有约束的不同模板
Pipeline class storing different templates with constraints
我有一个 class 模板 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
我想创建一个管道 class,它将多个 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 不是正确的方式。有人能指出我正确的方向吗?
解耦输入和输出调用。
数据传入和数据传出应该发生在不同的步骤。然后每个数据消费者都可以知道它需要什么,并为您进行转换(如果出现问题可能会抛出或错误标记)。
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) })
{}
};
我有一个 class 模板 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
我想创建一个管道 class,它将多个 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 不是正确的方式。有人能指出我正确的方向吗?
解耦输入和输出调用。
数据传入和数据传出应该发生在不同的步骤。然后每个数据消费者都可以知道它需要什么,并为您进行转换(如果出现问题可能会抛出或错误标记)。
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) })
{}
};