2

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;
}
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158

2 Answers2

3

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.

G. Sliepen
  • 7,637
  • 1
  • 15
  • 31
0

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.

Acorn
  • 24,970
  • 5
  • 40
  • 69