How to create a version of boost::range::transform that has an extra paramter for capturing context

169 Views Asked by At

For example I have a vector

std::vector<int> source;

and a struct

struct Foo {
 int x;
 int y;  
}

and I wish to do the following

Foo foo;
auto tr = source | boost::adaptors::transform([&](int i){return i+foo.x;};

However the above doesn't compile in the version of boost(1.55) and the compiler version(VS-2010) I am required to use. The problem is that when the lambda captures a variable by reference, the transform adaptor ends up trying to use the assign constructor which is illegal and fails to compile. However if nothing is captured then it all works.

My naive solution would be to wrap transform with another overload such that

Foo foo;
auto tr = source | boost::adaptors::transformed(foo, [](int i, Foo f){return i+f.x;};

This seems to be the pattern preferred by the std library. For example std::lower_bound uses this pattern.

but as soon as I try to think about how to do that I get stuck in template madness trying to wrap the original transform function. If somebody could show me how to generate the overload I require I am sure I could extrapolate that to the other overloads I need.

The alternative solution is instead of using lambdas is to use full functors for each function but this is ugly if I can at least use non capturing lambdas.

1

There are 1 best solutions below

1
On

All the machinery of boost::adaptors::transformed funnels down to boost::iterator::transform_iterator. transformed is a type alias, so transformed(fun) is constructing an object, it isn't a function call to be overloaded.

The simplest thing would be to copy iterator/transform_iterator.hpp and range/adaptor/transformed.hpp into a bitransform_iterator.hpp and bitransformed.hpp with an extra Param p (and rename UnaryFunctor to BinaryFunctor for clarity)