The specific error you've encountered appears because boost lambdas are not CopyAssignable. Here's a simpler way to achieve the same message:
auto f1 = _1 > 100;
auto f2 = f1;
f2 = f1; // same error
If you provide a CopyAssignable functor to filtered
, boost.phoenix (which you should be using anyway, boost.lambda is on the road to deprecation in favor of phoenix), a hand-written struct, or the old faithful std::bind2nd(std::greater<double>(), 100)
, this line compiles with clang++:
bind2nd demo: http://liveworkspace.org/code/2xKZIf
phoenix demo: http://liveworkspace.org/code/18425g
It fails with gcc due to some boost.concept check, which is probably a bug, but it's a moot point because the result of filtered
is boost::filtered_range
, whose iterators don't have the .index()
member function.
EDIT in response to comment:
comparing iterator into filtered_range with the iterator into the original vector wouldn't work. However, since you used vector, and since it's still accessible, you can compare addresses, since neither indexed
nor filtered
make copies
#include <vector>
#include <iostream>
#include <cassert>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/phoenix.hpp>
using namespace boost::adaptors;
using namespace boost::phoenix::placeholders;
int main ()
{
std::vector<double> x = {100, 150, 200, 110};
auto it = boost::max_element( x | indexed(0) | filtered(arg1 < 110) );
assert(&x[0] <= &*it && &*it < &x[0] + x.size());
std::cout << "Element " << *it << " is at index " << &*it - &x[0] << '\n';
}
demo http://liveworkspace.org/code/1zBIJ9
Or, for a more general solution, you could transform your vector into a vector of pairs (when boost gets zip adaptor, it could be neatly zipped with counting_range), and carry the original sequence index along with the value through all the transformations.