5

I'm learning C++ after having worked a lot with Haskell and functional languages in general, and I found that I'm constantly trying to solve the same problem:

  • Read some data from an input stream
  • Tokenize them based on a specific algorithm
  • Process the tokens

If this was Haskell, I could simply take advantage of the fact that everything is lazy, and write my transformation as I think about it, and then it would get applied as the downstream is being consumed. There are even libraries that do this exact pattern (conduit and pipes).

Let's say that I wanted to take the sequence 1 2 3 4 5 6 ... and output 12 34 56 .... I can see how to write ad-hoc code which operates on the stream and processes the data in place. But I'd like to know if there is an abstraction mechanism that allows me to build a new stream by transforming data (in any thinkable way) from another stream. This abstraction should allow me to buffer the data as I'm processing it, not just a simple mapping of a single element to a new value.

Here are the limitations:

  • I can't use any other library other than the stdlib.
  • It has to work on C++03 (meaning no C++11 features.)

If you're thinking, is this a homework? Well sort of, I'm getting a lot of class assignments which require me to work with streams of data (which is the reason for the no library and C++03 restrictions). It's not that I don't know how to do this using while loops, but I'd like to know if there is an existing stream abstraction in the stl, just waiting to be discovered and used.

But if the only way to do this is to use C++11, then I'd like to know.

Jakub Arnold
  • 85,596
  • 89
  • 230
  • 327
  • No ready-made package that I'm aware of. Perhaps a custom class type used with `std::istream_iterator`? – T.C. Oct 11 '14 at 11:09
  • @T.C. hmm, that might be what I'm looking for. If I understand correctly, I'd implement a custom iterator, which takes the input stream, and which produces the output that I need? What if I wanted to take one iterator and build another iterator from it (think composition)? – Jakub Arnold Oct 11 '14 at 11:19
  • I was thinking about a class with a custom stream extraction operator, used with [`std::istream_iterator`](http://en.cppreference.com/w/cpp/iterator/istream_iterator). As to composition, you would need to write your own iterator adaptors. – T.C. Oct 11 '14 at 11:45

2 Answers2

2

Concept code, not tested. Imaging there is lot of error checking and correct syntax.

struct add : public std::binary_function<int,int,int> {
  int operator() (int a, int b) {return (a + b);}
};

template<typename inType, typename dType, typename outType, class binFunc>
outType Transformer(inType& inStream, outType& outStream, binFunc func) {
  dType a, b;
  // Read some data from an input stream
  // Tokenize them based on a specific algorithm
  inStream>> a >> b; 
  //outStream << func(a, b);
  return func(a,b); // Process the tokens
}

int main() {
  std::ifstream in("input.dat", std::ifstream::in); // , std::ios::binary
  std::ofstream out("output.dat");
  struct add adder;  // to Process the tokens

  out << Transformer(in, out, adder);

  return exit_success;
}
Surt
  • 15,501
  • 3
  • 23
  • 39
0

The following doesn't fit your need of a no-library-solution (and I don't have enough reputation to leave it as a comment); however, it will be handy to your functional way of thinking.

David Sankel gave an excellent talk on FRP using C++ at C++Now 2014. He has even provided the library that they use for production.

The video can be found here: https://www.youtube.com/watch?v=tyaYLGQSr4g&list=UU5e__RG9K3cHrPotPABnrwg

The slides are linked on the video description and github links at the end of the slides.

I suspect you will also get inspiration from here: http://ericniebler.com/2013/11/07/input-iterators-vs-input-ranges/

std::transform with stream iterators should largely do what what you need.

mjcaisse
  • 221
  • 1
  • 4