使用可替换阶段在C ++中建模管道 [英] Modeling a pipeline in C++ with replaceable stages

查看:57
本文介绍了使用可替换阶段在C ++中建模管道的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试构想一个C ++数据结构,用于对一个简单的N阶段过程进行建模,其中每个阶段都可以用不同的函数替换。一种方法是使用OO方法,并在每个阶段都有一个带有虚拟方法的抽象基类。例如:

I am trying to concoct a C++ data structure for modeling a simple N stage process where each stage can be replaced with a different function. One way is to use the OO approach and have an abstract base class with a virtual method for each stage; e.g.:

class Pipeline {
protected:
  virtual void processA(const In& in, BType& B) = 0;
  virtual void processB(const BType& B, BType& C) = 0;
  virtual void processC(const CType& C, BType& D) = 0;
  virtual void processD(const DType& D, Out& out) = 0;
public:
  void process(const In& in, Out& out) {
    Btype B;
    processA(in, B);
    Ctype C;
    processB(B, C);
    Btype D;
    processC(C, D);
    processD(D,out);
  }
};

这种方法的问题是,如果N个阶段中的每个阶段都可以与M个过程互换,那么您就有N个* M个可能的子类。

The problem with this approach, if each of the N stages can be interchanged with M processes you have N*M possible subclasses.

另一个想法是存储函数对象:

Another idea is to store function objects:

class Pipeline {
public:
  std::function<void(const In& in, BType& B)> processA;
  std::function<void(const In& B, CType& C)> processB;
  std::function<void(const In& C, DType& D)> processC;
  std::function<void(const In& D, Out& out)> processD;
  void process(const In& in, Out& out) {
    Btype B;
    processA(in, B);
    Ctype C;
    processB(B, C);
    Btype D;
    processC(C, D);
    processD(D,out);
  }
};

这种方法的问题在于各个阶段并不是真正独立的,我想在某些情况下,单个对象可以存储有关多个阶段的信息。

The problem I am having with this approach is that the stages are not really independent and I would like a single object, in some cases, to store info concerning multiple stages.

有人找到了具有可更换部件的管道的良好数据结构吗?奖金可以使每个阶段同时运行。

Has anyone found a good data structure for a pipeline with replaceable parts? A bonus would be able to allow each stage to run concurrently.

推荐答案

要使您的第一种方法更具可互换性,您可以将抽象基类分为多个基类,每个进程一个。然后,可以通过一个或多个对象来实现基类。管道将保存对每个基类的引用,指针或智能指针:

To make your first approach more interchangeable you could split up the abstract base class into multiple base classes, one per process. Then the base classes can be implemented by one or many objects. The pipeline would hold a reference, pointer or smart-pointer to each base class:

struct ProcessA {
  virtual void processA(const In& in, BType& B) = 0;
  virtual ~ProcessA() = default;
};
struct ProcessB {
  virtual void processB(const BType& B, CType& C) = 0;
  virtual ~ProcessB() = default;
};
// ...

struct Pipeline {
  ProcessA* processA;
  ProcessB* processB;
  ProcessC* processC;
  ProcessD* processD;

  void process(const In& in, Out& out) {
    BType B;
    processA->processA(in, B);
    CType C;
    processB->processB(B, C);
    DType D;
    processC->processC(C, D);
    processD->processD(D,out);
  }
};

struct SimpleProcessor : ProcessA, ProcessB, ProcessC, ProcessD {
  void processA(const In& in, BType& B) override;
  void processB(const BType& B, CType& C) override;
  void processC(const CType& C, DType& D) override;
  void processD(const DType& D, Out& out) override;
};

int main() {
  SimpleProcessor processor;
  Pipeline pipeline;
  pipeline.processA = &processor;
  pipeline.processB = &processor; 
  pipeline.processC = &processor; 
  pipeline.processD = &processor; 
  In in;
  Out out;
  pipeline.process(in, out);
}

实时演示

您的第二种方法也可以工作。您可以使用lambda之类的方法来使单个对象适应每个 std :: function

Your second approach can work too. You can use something like a lambda to adapt a single object to fit each std::function:

struct Pipeline {
  std::function<void(const In& in, BType& B)>   processA;
  std::function<void(const BType& B, CType& C)> processB;
  std::function<void(const CType& C, DType& D)> processC;
  std::function<void(const DType& D, Out& out)> processD;

  void process(const In& in, Out& out) {
    BType B;
    processA(in, B);
    CType C;
    processB(B, C);
    DType D;
    processC(C, D);
    processD(D,out);
  }
};

int main() {
  SimpleProcessor proc;
  Pipeline pipeline;
  pipeline.processA = [&proc](const In& in, BType& B){ return proc.processA(in, B); };
  pipeline.processB = [&proc](const BType& B, CType& C){ return proc.processB(B, C); }; 
  pipeline.processC = [&proc](const CType& C, DType& D){ return proc.processC(C, D); }; 
  pipeline.processD = [&proc](const DType& D, Out& out){ return proc.processD(D, out); }; 
  In in;
  Out out;
  pipeline.process(in, out);
}

实时演示

是的,两种方法都允许您同时运行每个进程,但 BType CType DType 必须支持并发访问,以便可以编写它们同时阅读。例如并发队列。

And yes, either approach would allow you to run each process concurrently but your BType, CType and DType would have to support concurrent access so they can be written to and read from at the same time. Concurrent queues for example.

这篇关于使用可替换阶段在C ++中建模管道的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆