3

これは、フィルター処理された反復子で私が抱えている問題の単純化されたバージョンです (したがって、フィルターを回避するために別の方法で書き直すように依頼しても意味がありません)。奇妙なことに、実際のコードで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; });
                             ^

ラムダを修正に保存することは知っていstd::functionますが、その代償を払いたくありません。カスタム ラッパーを使用してstd::is_sortedも問題は解決しません。この問題は他の問題 (ブースト変換イテレータや c++11 lambdaなど) に関連しているように見えますが、そうではありません。少なくとも、それらの解決策はここには当てはまりません。

ありがとう!

4

1 に答える 1

8

シーケンスの反復処理に使用されるイテレータの内部is_sortedは、隣接する要素の比較に使用できるようにコピーされます。これは、述語 of filtered(つまり、ラムダ) もコピーする必要があることを意味しますが、実際には末尾の反復子をインクリメントするために使用されることはありません。イテレータをコピーする他のアルゴリズムにも同じ問題がありますadjacent_find

反復子をコピーするアルゴリズムとそうでないアルゴリズムの違いは、前者は「マルチパス」アルゴリズムと呼ばれ、反復子の型が を満たす必要がForwardIteratorあるのに対し、後者はシングルパスであり、 のみを必要とすることですInputIterator

解決策は、ラムダ ローカル スコープの有効期間を指定し、次のように渡すことreference_wrapperです。

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

別の方法は、次を使用してラムダを関数ポインターに強制すること+です。

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

ただし、これはキャプチャレス ラムダでのみ機能し、不明確になる可能性があります。

于 2014-09-18T08:02:52.267 に答える