C ++: how to find max_element using boost :: range?

I am trying to return an iterator to the largest element in the filtered range. Here is what I still have:

#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 the index in the vector x, which has the largest element (i.e. 2), but unfortunately it does not compile (Linux 64bit, GCC 4.7.2), the problem is in the line above, First The compilation error that I get from the compiler (among others) is this:

/boost/tuple/detail/tuple_basic.hpphaps96:36: error: assigning read-only member 'boost :: tuples :: cons :: head

Any ideas what I'm doing wrong? Or how else can I achieve what I'm trying to do? Thanks in advance!

EDIT:

Change the problem line to:

 auto it = boost::max_element<boost::return_found>(x | sliced(1,4) | filtered(boost::function<bool(double)>(_1>100))); 
It seems that

returns the iterator to the largest element. However, is there a way to verify that the iterator is within range? Comparing it to boost :: end (x) gives me an error. The only thing I can think of is 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.

+4
source share
1 answer

The specific error you are encountering appears because boost lambdas are not CopyAssignable. Here's an easier way to get the same message:

 auto f1 = _1 > 100; auto f2 = f1; f2 = f1; // same error 

If you provide CopyAssignable functor for filtered , boost.phoenix (which you should use anyway, boost.lambda is on the way to obsolescence in favor of phoenix), a handwritten structure or the old faithful std::bind2nd(std::greater<double>(), 100) , this line is compiled using clang ++:

bind2nd demo: http://liveworkspace.org/code/2xKZIf

phoenix demo: http://liveworkspace.org/code/18425g

It does not work with gcc due to some boost.concept check, which is probably a bug, but this is a moot point, because the result of filtered is boost::filtered_range , whose iterators do not have a member function .index() .

EDIT in response to a comment: comparing an iterator in filter_range with an iterator in the original vector will not work. However, since you used the vector and since it is still available, 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 can convert the vector to a vector of pairs (when boost receives a zip adapter, it can be carefully archived with counting_range) and carry the original index of the sequence along with the value through all the conversions.

+4
source

All Articles