The most difficult problem is figuring out the return type in the code. decltype
and lambdas do not mix well (see here), so we have to think of an alternative way:
auto map = boost::adaptors::transformed;
namespace magic_transform
{
std::function<int(int)> f1 = [](int x){ return 2*x; };
std::function<int(int)> f2 = [](int x){ return x+1; };
template <typename Range>
auto run_pipeline(Range input) -> decltype(input | map(f1) | map(f1))
{
return input | map(f1) | map(f2);
}
}
...
auto sink = magic_transform::run_pipeline(generate(1))
| map([](int x){ return 3*x; });
The simple solution is stick the lambdas into std::function
so we can use decltype
to deduce the return type. I used namespace magic_transform
in the example, but you could adapt this code into a class if you would like also. Here is a link adapting your code to the above.
Also, using std::function
might be overkill here. Instead you could just declare two normal functions instead (example).
I was also experimenting with boost::any_range
, there seems to be some incompatibilities with C+11 lambdas, etc. The closest I could get was the following (example):
auto map = boost::adaptors::transformed;
using range = boost::any_range<
const int,
boost::forward_traversal_tag,
const int&,
std::ptrdiff_t
>;
namespace magic_transform
{
template <typename Range>
range run_pipeline(Range r)
{
return r | map(std::function<int(int)>([](int x){ return 2*x; }))
| map(std::function<int(int)>([](int x){ return x+1; }));
}
}
int main(){
auto sink = magic_transform::run_pipeline(boost::irange(0, 10))
| map([](int x){ return 3*x; });
for(auto i : sink)
std::cout << i << "\n";
}