简体   繁体   English

C ++ std :: iterator,不在内部使用std :: vector或std :: list

[英]C++ std::iterator without using std::vector or std::list internally

I'm trying (as an exercise) to create a simple numeric range class in C++. 我正在尝试(作为练习)在C ++中创建一个简单的数值范围类。 It will let you iterate through evenly spaced doubles (like the numpy/Python arange ): 它会让你迭代均匀间隔的双精度(如numpy / Python arange ):

What I'd like to do (but with an iterator): 我想做什么(但使用迭代器):

double lower = ..., upper = ..., delta = ...;
for (double val = lower; val < upper; val += delta)
{
   // do something with val
   f(val);
}
// include the last val to guarantee upper is included or exceeded
f(val); // do something with val

Desired equivalent iterator code: 期望的等效迭代器代码:

double lower = ..., upper = ..., delta = ...;
NumericRange nr(lower, upper, delta);
for (NumericRange::const_iterator iter = nr.begin(); iter != nr.end(); iter++)
{
    f(*iter);
}

I'd like my iterator to be compatible with STL iterators so I can reuse code (iterating through a NumericRange should be equivalent to iterating through std::vector). 我希望我的迭代器与STL迭代器兼容,所以我可以重用代码(迭代通过NumericRange应该相当于迭代通过std :: vector)。

I've had success simply storing the values in a std::vector (and then using the std::vector's iterator). 我只是成功地将值存储在std :: vector中(然后使用std :: vector的迭代器)。 This is how everything I've found online has solved this problem. 这就是我在网上发现的一切都解决了这个问题。 However, it really isn't necessary to store the entire list. 但是,实际上没有必要存储整个列表。

Is there a way to avoid storing the entire set of values? 有没有办法避免存储整个值集? Is there some iterable class I can inherit from and override ++ , == , etc. to get the desired effect without storing the std::vector<double> ? 是否有一些iterable类我可以继承并覆盖++==等以获得所需的效果而不存储std::vector<double>

(I'd really like to know how to do this without BOOST, even though it's great. I'm asking this because I'd like to learn how to write (from scratch) something like a BOOST solution. I definitely know that part of software engineering is using the tools created by others, but I really want to learn how those tools are designed and built.) (我真的很想知道如何在没有BOOST的情况下做到这一点,即使它很棒。我问这个是因为我想学习如何 (从头开始)像BOOST解决方案。我当然知道那部分软件工程正在使用其他人创建的工具,但我真的想了解这些工具是如何设计和构建的。)

My iterable NumericRange class (using std::vector<double> internally): 我的可迭代NumericRange类(在内部使用std::vector<double> ):

class NumericRange
{
protected:
  double lower, upper, delta;
  std::vector<double> sorted_range;
public:
  typedef std::vector<double>::const_iterator const_iterator;
  NumericRange()
  {
    lower = upper = delta = std::numeric_limits<double>::quiet_NaN();
    // vector is constructed empty
  }
  NumericRange(double lower_param, double upper_param, double delta_param)
  {
    lower = lower_param;

    upper = upper_param;
    delta = delta_param;
    assert(upper_param > lower_param);

    double val;
    // note: can be much faster without push_back
    for (val = lower_param; val < upper_param; val += delta_param)
      {
    sorted_range.push_back(val);
      }
    // ensure the upper_value is contained or surpassed
    sorted_range.push_back(val);
  }
  // to prevent comparison of the entire vector
  bool operator ==(const NumericRange & rhs) const
  {
    return lower == rhs.lower && upper == rhs.upper && delta == rhs.delta;
  }
  // note: this class doesn't really need to store the values in a
  // vector, but it makes the iterator interface much easier.
  const_iterator begin() const
  {
    return sorted_range.begin();
  }
  const_iterator end() const
  {
    return sorted_range.end();
  }
  double get_lower() const
  {
    return lower;
  }
  double get_upper() const
  {
    return upper;
  }
  double get_delta() const
  {
    return delta;
  }
  size_t size() const
  {
    return sorted_range.size();
  }
  void print() const
  {
    std::cout << "[ " << lower << " : " << upper << ": +=" << delta << " ]" << std::endl;
  }
};

Is there some iterable class I can inherit from and override ++ , == , etc. to get the desired effect without storing the std::vector<double> ? 是否有一些可迭代的类我可以继承并覆盖++==等以获得所需的效果而不存储std::vector<double>

Yes, there is. 就在这里。 Its name is std::iterator<std::input_iterator_tag, double> . 它的名字是std::iterator<std::input_iterator_tag, double>

Here is a start for you, using int . 这是一个使用int的开始。 To save space in my brain, I use the same class to represent both the range and the iterator. 为了节省大脑空间,我使用相同的类来表示范围和迭代器。

#include <iterator>
#include <iostream>

struct NumericRange : public std::iterator< std::input_iterator_tag, int >
{
  int current, fini, delta;
  typedef NumericRange iterator;
  typedef iterator const_iterator;
  iterator begin() { return *this; }
  iterator end() { return iterator(fini, fini, delta); }
  iterator& operator++() { current += delta; return *this; }
  iterator operator++(int) { iterator result(*this); ++*this; return result; }
  int operator*() const { return current; }
  NumericRange(int start, int fini, int delta) 
    : current(start), fini(fini), delta(delta)
  {
  }
  bool operator==(const iterator& rhs) {
    return rhs.current == current;
  }
  bool operator!=(const iterator& rhs) {
    return !(*this == rhs);
  }
};

void f(int i, int j) {
  std::cout << i << " " << j << "\n";
}

int main () {
  int lower = 4, upper = 14, delta = 5;
  NumericRange nr(lower, upper, delta);
  for (NumericRange::const_iterator iter = nr.begin(); iter != nr.end(); iter++)
  {
      f(*iter, *nr.end());
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM