C++: how to find max_element using boost::range?
boost, boost-lambda, boost-range, c++
Solution
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.
Problem
I am trying to return an iterator to the largest element in a filtered range. Here is what I have so far: ``` #include <boost/lambda/lambda.hpp> #include <boost/range/adaptors.hpp> #include <boost/range/algorithm.hpp> #include <vector> #include <iostream> using namespace boost::adaptors; using namespace boost::lambda; using namespace std; int main () { vector<double> x = {100, 150, 200, 110}; auto it = boost::max_element(x | indexed(0) | filtered(_1>100)); /* problem here */ cout << it.index() << endl; return 0; } ``` I expected the code to print out the index in the vector x which has the largest element (ie 2), but unfortunately it does not compile (Linux 64bit, GCC 4.7.2), the problem being in the line indicated above. The first compilation error I get from the compiler (amongst others) is the following: /boost/tuple/detail/tuple_basic.hpp:396:36: error: assignment of read-only member ‘boost::tuples::cons::head’ Any ideas what I am doing wrong? Or how else I can achieve what I am trying to do? Thanks in advance! EDIT: Changing the problematic line to : ``` auto it = boost::max_element<boost::return_found>(x | sliced(1,4) | filtered(boost::function<bool(double)>(_1>100))); ``` seems to return the iterator to the largest element. However, is there a way to check that the iterator is within the range? Comparing it with boost::end(x) gives me an error. The only thing I can think of is to return ``` auto another_range = boost::max_element<boost::return_found_end>(x | sliced(1,4) | filtered(boost::function<bool(double)>(_1>100))); ``` and check if boost::empty(another_range). Is this the only option? Thanks.