Trying to create pipeline pattern with c++

Viewed 1297

I am trying to build the following in my head in c++, but seems like there is no good translation of java to c++ for everything, here is what I am trying to accomplish:

  1. create a pipeline that each steps has an input and output (outputs are fed to the next step)
  2. process pipeline end to end:
public interface Step<I, O> {
    public static class StepException extends RuntimeException {
        public StepException(Throwable t) {
            super(t);   
        }
    }
    public O process(I input) throws StepException;
}
public class Pipeline<I, O> {
    private final Step<I, O> current;
    private Pipeline(Step<I, O> current) {
        this.current = current;
    }

    private <NewO> Pipeline<I, NewO> pipe(Step<O, NewO> next) {
        return new Pipeline<>(input -> next.process(current.process(input)));
    }
    
    public O execute(I input) throws Step.StepException {
        return current.process(input);
    }
}
public class ExamplePipeline {
    public static class AdditionInput {
        public final int int1;
        public final int int2;
        
        public AdditionInput(int int1, int int2) {
            this.int1 = int1;
            this.int2 = int2;
        }
    }
    public static class AddIntegersStep implements Step<AdditionInput, Integer> {
        public Integer process(AdditionInput input) {
            return input.int1 + input.int2;   
        }
    }
    
    public static class IntToStringStep implements Step<Integer, String> {
        public String process(Integer input) {
            return input.toString();
        }
    }
    
    public static void main(String[] args) {
        Pipeline<AdditionInput, String> pipeline = new Pipeline<>(new AddIntegersStep())
            .pipe(new IntToStringStep());
        System.out.println(pipeline.execute(new AdditionInput(1, 3))); // outputs 4
    }
}

How can I model the above in c++?

I cant get the pipeline modeled, step is pretty simple:

template <typename I>
template <typename O>
class Step {
  virtual O process(I input) = 0;

 public:
  typedef I inputType;
  typedef O outputType;
}
2 Answers

I think there are multiple ways this problem can be solved. Here is a way using lambdas:

auto pipe = [](auto a, auto b){ return [&](auto c){ return b(a(c)); }; };

And an example program using it:

#include <iostream>
#include <string>

auto pipe = [](auto a, auto b){ return [&](auto c){ return b(a(c)); }; };

int main() {
    auto Addition = [](std::pair<int, int> p) {return p.first + p.second;};
    auto IntToString = [](int a) {return std::to_string(a);};
    auto AddNewline = [](std::string a) {return a + "\n";};

    auto pipeline = pipe(pipe(Addition, IntToString), AddNewline);

    std::cout << pipeline(std::pair<int, int>{1, 3});
}

Another interesting approach, that will allow you to create a pipeline using the |-operator can be found in this answer.

There are several ways to do this depending on how flexible, fast or simple the solution needs to be.

If you don't need to build/store the individual steps in the pipeline at runtime to call them later on, then you can do something pretty similar to the Java example, like modelling each step as a callable type and then have your pipe member function be a template which applies the step passed as a parameter.

Related