C ++:如何使用boost :: range查找max_element?

时间:2013-03-30 21:52:02

标签: c++ boost boost-lambda boost-range

我试图将迭代器返回到过滤范围中的最大元素。以下是我到目前为止的情况:

#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;
}

我希望代码打印出矢量x中具有最大元素(即2)的索引,但遗憾的是它不能编译(Linux 64bit,GCC 4.7.2),问题出现在上面指出的行中。我从编译器(以及其他)获得的第一个编译错误如下:

/boost/tuple/detail/tuple_basic.hpp:396:36:错误:只读成员'boost :: tuples :: cons :: head'的分配

任何想法我做错了什么?或者我怎么能实现我想做的事情呢?提前谢谢!

编辑:

将有问题的行更改为:

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

似乎将迭代器返回到最大元素。但是,有没有办法检查迭代器是否在范围内?将它与boost :: end(x)进行比较会给我一个错误。我唯一能想到的就是返回

auto another_range = boost::max_element<boost::return_found_end>(x | sliced(1,4) |   filtered(boost::function<bool(double)>(_1>100)));

并检查boost :: empty(another_range)。这是唯一的选择吗?感谢。

1 个答案:

答案 0 :(得分:4)

您遇到的具体错误是因为boost lambdas不是CopyAssignable。这是实现相同信息的更简单方法:

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

如果你向filtered提供一个CopyAssignable仿函数,boost.phoenix(无论如何你应该使用它,boost.lambda正在弃用而不是凤凰),一个手写的结构,或者老忠实std::bind2nd(std::greater<double>(), 100),这一行用clang ++编译:

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

凤凰演示:http://liveworkspace.org/code/18425g

由于某些boost.concept检查而导致gcc失败,这可能是一个bug,但这是一个没有实际意义的点,因为filtered的结果是boost::filtered_range,其迭代器没有.index() {1}}成员函数。

编辑回应评论: 将迭代器与filtered_range进行比较,将迭代器与原始向量进行比较是行不通的。但是,由于您使用了向量,并且因为它仍然可以访问,因此您可以比较地址,因为indexedfiltered都不会复制

#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

或者,对于更通用的解决方案,您可以将矢量转换为对矢量(当boost获取zip适配器时,可以使用counting_range整齐地压缩),并将原始序列索引与值一起传递到所有变换。