0

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.

bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
  • can you modify the code so it's in the form of a complete compilation unit, along with correct includes? That way, it's easier for us to play with – Richard Hodges May 14 '18 at 15:20
  • `boost::adaptors::transform` is the non-`|` version. I think you mean `boost::adaptors::transformed`, which works fine with capturing lambdas – Caleth May 14 '18 at 15:26
  • @caleth I meant transformed. Fixed now – bradgonesurfing May 14 '18 at 15:35
  • @RichardHodges On Godbolt https://godbolt.org/g/cHm7g9 I can't pick the version of boost with the bug though on goldbolt. 1.55 – bradgonesurfing May 14 '18 at 15:35
  • @Caleth The problem is due to an old version of boost and an old version of visual studio. The error is a bug in boost 1.55 – bradgonesurfing May 14 '18 at 15:36
  • You just need to have a valid everything else: https://godbolt.org/g/H4SRfR – Caleth May 14 '18 at 15:40
  • @Caleth I know that works. The problem is with an old boost and old compiler. I'm not asking for anybody to prove that linked code compiles. I know it does under perfect conditions. I'm asking how to wrap transformed so that I use a different mechanism for capturing context. – bradgonesurfing May 14 '18 at 15:52
  • 1
    Have you tried capturing a `std::reference_wrapper` by value? – Caleth May 14 '18 at 16:01
  • @Caleth the problem is I that as soon as the compiler generates a functor rather than a function pointer boost::transform fails. I am asking a specific question. How to wrap boost::adaptors::transformed. I'm not asking how to fix the bug. – bradgonesurfing May 14 '18 at 16:03

1 Answers1

1

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)

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • Thanks for answering the question in the direction Im looking for +1. Any chance you would fill out the answer with more detail. I guess what dissapoints me about boost::range is the non trivial way to compose and build on existing infrastructure. I assumed naively that I could easily wrap **transformed** in a function but it seems, as you point out, you always have to start at zero and build again to implement extended features. Again thanks for the pointers. – bradgonesurfing May 14 '18 at 18:11