Lazy Transform In C++
Solution 1:
Employing Boost.Range:
intmain(){
auto map = boost::adaptors::transformed; // shorten the nameauto sink = generate(1) | map([](int x){ return2*x; })
| map([](int x){ return x+1; })
| map([](int x){ return3*x; });
for(auto i : sink)
std::cout << i << "\n";
}
Solution 2:
I think the most idiomatic way to do this in C++ is with iterators. Here is a basic iterator class that takes an iterator and applies a function to its result:
template<classIterator, classFunction>
classLazyIterMap
{
private:
Iterator i;
Function f;
public:
LazyIterMap(Iterator i, Function f) : i(i), f(f) {}
decltype(f(*i)) operator* () { returnf(*i); }
void operator++ () { ++i; }
};
template<classIterator, classFunction>
LazyIterMap<Iterator, Function> makeLazyIterMap(Iterator i, Function f)
{
returnLazyIterMap<Iterator, Function>(i, f);
}
This is just a basic example and is still incomplete as it has no way to check if you've reached the end of the iterable sequence.
Here's a recreation of your example python code (also defining a simple infinite counter class).
#include<iostream>classCounter
{
public:
Counter (int start) : value(start) {}
intoperator* () { return value; }
voidoperator++ () { ++value; }
private:
int value;
};
intmain(int argc, charconst *argv[]){
Counter source(0);
auto pipe1 = makeLazyIterMap(source, [](int n) { return2 * n; });
auto pipe2 = makeLazyIterMap(pipe1, [](int n) { return n + 1; });
auto sink = makeLazyIterMap(pipe2, [](int n) { return3 * n; });
for (int i = 0; i < 10; ++i, ++sink)
{
std::cout << *sink << std::endl;
}
}
Apart from the class definitions (which are just reproducing what the python library functions do), the code is about as long as the python version.
Solution 3:
I think the boost::rangex library is what you are looking for. It should work nicely with the new c++lambda syntax.
Solution 4:
intpipe1(int val){
return2*val;
}
intpipe2(int val){
return val+1;
}
intsink(int val){
return val*3;
}
for(int i=0; i < SOME_MAX; ++i)
{
cout << sink(pipe2(pipe1(i))) << endl;
}
I know, it's not quite what you were expecting, but it certainly evaluates at the time you want it to, although not with an iterator iterface. A very related article is this:
Edit 6/Nov/12:
An alternative, still sticking to bare C++, is to use function pointers and construct your own piping for the above functions (vector of function pointers from SO q: How can I store function pointer in vector?):
typedef std::vector<int (*)(int)> funcVec;
intrunPipe(funcVec funcs, int sinkVal){
int running = sinkVal;
for(funcVec::iterator it = funcs.begin(); it != funcs.end(); ++it) {
running = (*(*it))(running); // not sure of the braces and asterisks here
}
return running;
}
This is intended to run through all the functions in a vector of such and return the resulting value. Then you can:
funcVec funcs;
funcs.pushback(&pipe1);
funcs.pushback(&pipe2);
funcs.pushback(&sink);
for(int i=0; i < SOME_MAX; ++i)
{
cout << runPipe(funcs, i) << endl;
}
Of course you could also construct a wrapper for that via a struct (I would use a closure if C++ did them...):
structpipeWork {
funcVec funcs;
intrun(int i);
};
intpipeWork::run(int i){
//... guts as runPipe, or keep it separate and call:returnrunPipe(funcs, i);
}
// later...
pipeWork kitchen;
kitchen.funcs = someFuncs;
int (*foo) = &kitchen.run();
cout << foo(5) << endl;
Or something like that. Caveat: No idea what this will do if the pointers are passed between threads.
Extra caveat: If you want to do this with varying function interfaces, you will end up having to have a load of void *(void *)(void *)
functions so that they can take whatever and emit whatever, or lots of templating to fix the kind of pipe you have. I suppose ideally you'd construct different kinds of pipe for different interfaces between functions, so that a | b | c
works even when they are passing different types between them. But I'm going to guess that that's largely what the Boost stuff is doing.
Solution 5:
Depending on the simplicity of the functions :
#define pipe1(x) 2*x#define pipe2(x) pipe1(x)+1#define sink(x) pipe2(x)*3int j = 1while( ++j > 0 )
{
std::cout << sink(j) << std::endl;
}
Post a Comment for "Lazy Transform In C++"