过滤范围,lambdas和is_sorted

时间:2014-09-18 07:39:40

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

这是我对过滤迭代器的一个问题的简化版本(因此,要求我以不同方式重写它以避免过滤器没有意义)。奇怪的是,在实际代码中只有is_sorted似乎问题,其他用途似乎工作正常。

#include <vector>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm_ext/is_sorted.hpp>

int main(int argc, const char* argv[])
{
  using namespace boost::adaptors;
  std::vector<int> all = {1,2,3,4,5,6,7,8,9};
  auto some = all | filtered([] (int i) { return i % 2; });
  return boost::is_sorted(some);
}

无法使用Clang ++ 3.5和G ++ 4.9进行编译(在Mac OS X上,最新):

$ clang++-mp-3.5 -std=c++11 -isystem /opt/local/include/ foo.cc
In file included from foo.cc:3:
In file included from /opt/local/include/boost/range/algorithm_ext/is_sorted.hpp:18:
/opt/local/include/boost/detail/is_sorted.hpp:25:28: error: object of type
      'boost::filter_iterator<(lambda at foo.cc:9:30), std::__1::__wrap_iter<int
      *> >' cannot be assigned because its copy assignment operator is
      implicitly deleted
  for (; it != last; first = it, ++it)
                           ^
...

/opt/local/include/boost/iterator/filter_iterator.hpp:106:17: note: copy
      assignment operator of 'filter_iterator<(lambda at foo.cc:9:30),
      std::__1::__wrap_iter<int *> >' is implicitly deleted because field
      'm_predicate' has a deleted copy assignment operator
      Predicate m_predicate;
                ^
foo.cc:9:30: note: lambda expression begins here
  auto some = all | filtered([] (int i) { return i % 2; });
                             ^

我知道将我的lambda存储在std::function修复它,但我想避免支付 它的价格。在std::is_sorted周围使用自定义包装并不能解决问题。这个问题似乎与其他问题有关(例如boost transform iterator and c++11 lambda), 但事实并非如此 - 至少他们的治疗不适用于此。

谢谢!

1 个答案:

答案 0 :(得分:7)

is_sorted内部,复制用于迭代序列的迭代器,以便它可用于比较相邻元素。这意味着filtered(即你的lambda)的谓词也需要被复制,即使它实际上从未用于递增尾随迭代器。复制迭代器的其他算法也会遇到同样的问题,例如: adjacent_find

复制迭代器的算法和不复制迭代器的算法之间的区别在于前者被称为&#34; multipass&#34;算法,并要求它们的迭代器类型满足ForwardIterator,而后者是单遍的,只需要InputIterator

解决方案是给你的lambda本地范围生命周期并通过reference_wrapper传递它:

auto odd = [] (int i) { return i % 2; };
auto some = all | filtered(std::ref(odd));

另一种选择是coerce your lambda to a function pointer using +

auto some = all | filtered(+[] (int i) { return i % 2; });

但这只适用于无捕捉的lambdas,并且可能不清楚。