将boost :: transform_iterator与非const仿函数一起使用

时间:2012-10-10 13:07:53

标签: c++ boost

我想使用transform_iterator对范围进行增量转换。通过delta变换,我的意思是r 0 应保持不变,后续元素r i 映射到(r i - r < sub> i - 1 )。

我的问题是,据我所知,transform_iterator需要一个const仿函数,但我的仿函数需要记住以前的值。我怎么解决这个问题?我应该编写自己的迭代器吗?

我希望它作为迭代器的原因是,在下一步中我想从中创建一个范围适配器。

编辑: 似乎transform_iterator确实允许非const仿函数,并且它真的是我的范围适配器抱怨缺乏constness。我会保持问题公开,因为无论如何讨论使用transform_iterator是多么合适似乎很有趣。

2 个答案:

答案 0 :(得分: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;
}

要真正做到这一点,你需要知道迭代器何时进展,所以我认为你需要自己的迭代器。

答案 1 :(得分:3)

这似乎对我来说很好,即使我用指针记住 以前的价值(可能是也可能不是你的好主意 情况)。

#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,它也不会使用lambda,因为有状态的lambda必须被标记为可变,并且你不能像使用可变成员一样隐藏副作用。