4

transform_iteratorを使用して、範囲でデルタ変換を行いたい。デルタ変換とは、r 0が同じままであり、後続の要素r iが(r i --r i -1)にマップされることを意味します。

私の問題は、transform_iteratorにはconstファンクターが必要であると言える限り、私のファンクターは前の値を覚えておく必要があるということです。どうすればこれを解決できますか?自分のイテレータを書くだけでいいですか?

イテレータとして必要な理由は、次のステップでそれからレンジアダプタを作成したいからです。

編集:transform_iteratorは非constファンクターを許可しているようで、constnessの欠如について不平を言ったのは本当に私のレンジアダプターだったようです。とにかくtransform_iteratorを使用することがどれほど適切であるかについての議論は興味深いように思われるので、私は質問を開いたままにしておきます。

4

2 に答える 2

4

boost::transform_iteratorでこれを完全に正しく機能させることはできないと思います。これは、最初は機能するように見える単純な実装ですが、実際にはうまく機能しません。

#include <boost/iterator/transform_iterator.hpp>
#include <vector>
#include <iostream>

using std::cout;

struct Delta {
  Delta() : prev_value(0) { }

  int operator()(int value) const
  {
    int result = value-prev_value;
    prev_value = value;
    return result;
  }

  mutable int prev_value;
};

int main(int,char**)
{
  typedef std::vector<int> Items;
  typedef boost::transform_iterator<Delta,Items::iterator,int> Iter;

  Items items;
  items.push_back(4);
  items.push_back(3);
  items.push_back(8);
  { // prints 4 -1 5  -- excellent
    Iter i(items.begin(),Delta()), end(items.end(),Delta());
    for (;i!=end;++i) {
      cout << *i << " ";
    }
    cout << "\n";
  } 
  { // prints 4 0 -- crap
    Iter i(items.begin(),Delta());
    cout << *i << " ";
    cout << *i << "\n";
  }
  return 0;
}

これを実際に機能させるには、イテレータがいつ進歩するかを知る必要があるので、独自のイテレータが必要になると思います。

于 2012-10-10T13:45:29.363 に答える
4

これは、以前の値を記憶するためにポインターを使用する場合でも、私にとってはうまく機能しているようです(これは、あなたの場合は良い考えかもしれませんし、そうでないかもしれません)。

#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/iterator/transform_iterator.hpp>

class delta {
public:
  typedef int result_type;

  int operator()(const int& i) const {
    if(prev) {
      const int* tmp = prev;
      prev = &i;
      return i - *tmp;
    } else {
      prev = &i;
      return i;
    }
  }
private:
  mutable const int* prev = nullptr;
};

int main()
{
  std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  std::for_each(boost::make_transform_iterator(begin(v), delta()), 
                boost::make_transform_iterator(end(v), delta()),
                [](int i) { std::cout << i << std::endl; });

  return 0;
}

ただし、decltypeを使用している場合でも、ラムダでは機能しません。ステートフルラムダは可変としてマークする必要があり、可変メンバーの場合のように副作用を隠すことができないためです。

于 2012-10-10T13:58:29.133 に答える