【问题标题】:Use boost::transform_iterator with a non-const functor将 boost::transform_iterator 与非常量函子一起使用
【发布时间】:2014-02-24 01:05:00
【问题描述】:

我想使用 transform_iterator 在范围上进行增量转换。通过增量转换,我的意思是 r0 应该保持不变,并且后续元素 ri 映射到 (ri - ri - 1).

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

我想要它作为迭代器的原因是在下一步中我想用它制作一个范围适配器。

编辑: 似乎 transform_iterator 确实允许非常量函子,而且确实是我的范围适配器抱怨缺乏 constness。我将保持这个问题的开放性,因为关于使用 transform_iterator 是否合适的讨论似乎很有趣。

【问题讨论】:

  • partial_sum 是个好建议!不过,我这样做部分是为了学习如何制作范围适配器。迭代器也是惰性的,而算法不是。在使用 partial_sum 的某些条件(例如第一个非零增量)之前,我无法迭代无限系列的增量。
  • 实际上,我想我的意思是std::adjacent_difference。不过听上去,你可能需要 std::find_if 和一个累积的谓词对象。

标签: c++ boost


【解决方案1】:

我认为你不能使用 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;
}

要真正完成这项工作,您需要知道迭代器何时高级,所以我认为您需要自己的迭代器。

【讨论】:

  • 是的,你是对的。当您使用 iterator_facade 执行自己的迭代器时,这一点更加明显,因为取消引用是 const 而增量不是。
【解决方案2】:

这对我来说似乎工作得很好,即使我使用指针来记住 以前的值(在您的 案例)。

#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 必须标记为可变,并且您不能像使用可变成员那样隐藏副作用。

【讨论】:

    猜你喜欢
    • 2012-07-30
    • 2011-07-11
    • 1970-01-01
    • 2017-12-27
    • 1970-01-01
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多