0

所以我们知道 foreach 是这样的:

template<class InputIterator, class Function>
  Function for_each(InputIterator first, InputIterator last, Function f)
  {
    for ( ; first!=last; ++first ) f(*first);
    return f;
  }

我已经实施了一个

template <typename T>
class Range

问题是当我将此函数与 for_Each 一起使用时:

static void add1(float &v)
{
  ++v;
}

由于第一个“!=”最后一个(它不是第一个“<”最后一个),它进入无限循环,那么当人们实现自己的前向迭代器以使用 for_each 时,他们会怎么做?

4

3 回答 3

4

您的方法的问题是您的迭代器增量运算符不会更改迭代器,而是更改存储的值。这意味着在for_each循环内部,条件在迭代器的增量运算符和函数中都被修改。

于 2012-05-26T23:46:50.783 回答
0

无论如何,您要达到什么目的……您的班级是否有任何内部存储空间,还是仅代表数字序列?

如果是这样,那么问题出在运算符上T &operator*()T *operator->()它们允许更改迭代器指向的值。但如果它只是范围类,它显然不能以这种方式编辑,你应该使用cons_iterator.

如果你的类有一个内部存储,那么你的交互器应该有指向它的指针(T* pData_;而不是T pData_;),然后你不需要删除星号,T &operator*() 其中令人惊讶的是已经为正确的版本做好了准备;)关键是 incrementivg 迭代器应该增加这个指针并增加值在你的add1函数中应该增加指向值。现在这两个操作都增加了同一个变量,所以你得到了那些+=2.

编辑:

@DavidRodríguez-dribeas - 您正在考虑不同的输入迭代器类别,这些类别旨在描述允许的顺序访问(可以访问哪些序列元素)之间的区别,但所描述的问题是Range类实例是设计常量(至少不是可以仅使用迭代器进行修改)。我看不出任何反对给予它随机访问类别的东西。

唯一的选择是在任何地方都用 const_iterator 替换迭代器,这样迭代的值就不能被修改。现在这有点违反 ISO C++,它将容器分为几个类别,并且对于它需要的每个类别,begin()并且只有在容器本身被声明时才end()返回。但是我认为在 ISO C++ 视图中类甚至是容器是有争议的,因为(根据 23.1.1)const_iteratorconstRange

容器是存储其他对象的对象。它们通过构造函数、析构函数、插入和擦除操作来控制这些对象的分配和释放。

在 Range 类中似乎没有任何实际的迭代对象存储,我认为我们在这里很疯狂,不需要那么遵守标准。

编辑2:

首先const iterator是不一样的const_iterator。第一个是无法更改的迭代器(指向序列中的不同值,例如递增),另一个允许这样做,但不允许更改指向的值,因此(*i)=3会失败。

其次,我会这样做:

template <typename T>
class Range {
public: 
    class const_iterator;
    typedef const_iterator iterator; //For stl-compliance - some algorythms use that.

    IntegerRange(T low, T high) : low_(low), high_(high) { assert(low <= high);}
    const_iterator begin() const { return const_iterator(low_); }
    const_iterator end() const { return const_iterator(high_); }
private:
    const T low_;
    const T high_;
};

template<typename T>
class Range<T>::const_iterator : public std::iterator<std::forward_iterator_tag, T>
{
public:

 // default constructor                                                                         
  const_iterator() : pData_(0)
  {
  }

  // constructor from const T&                                                                   
  const_iterator(const T &pData) : pData_(pData)
  {
  }

  // constructor from T&                                                                         
  const_iterator(T &pData) : pData_(pData)
  {
  }

  // operator =                                                                                  
  const_iterator &operator=(const const_iterator &other)
  {
    this->pData_ = other.pData_;
    return *this;
  }


  // pre-increment operator                                                                      
  const_iterator & operator++()
  {
    ++(this->pData_);
    return *this;
  }
  // post-increment operator                                                                     
  const_iterator operator++(int)
  {
    const_iterator temp(*this);
    this->operator++();
    return temp;
  }

  // operator ==                                                                                 
  bool operator==(const const_iterator &other) const
  {
    return this->pData_ == other.pData_;
  }

  // operator !=                                                                                 
  bool operator!=(const iterator &other) const
  {
    return !operator==(other);
  }

  // operator* r-value                                                                           
  const T &operator*() const
  {
    return (this->pData_); // had to remove the *                                                
  }

  // operator-> r-value                                                                          
  const T *operator->() const
  {
    return &(this->pData_);
  }

private:
  T pData_;
};

只要您遵守 const_iterator 规范,您显然可以自由地保留名称迭代器而不是 const_iterator(或使用 qqwfmnghng 作为类名) - 在这种情况下,不提供左值运算符,因为它们旨在修改指向值 - 什么这有意义吗?

于 2012-05-26T23:57:55.553 回答
0
#include <assert.h>     // assert
#include <iterator>     // std::forward_iterator
#include <utility>      // std::pair
#include <stddef.h>     // ptrdiff_t, size_t

typedef size_t          UnsignedSize;
typedef ptrdiff_t       Size;
typedef Size            Index;

template< class TpValue >
class ValueRange
{
public:
    typedef TpValue     Value;

private:
    Value   first_;
    Size    span_;

public:
    class It
        : public std::iterator< std::forward_iterator_tag, Value >
    {
    friend class ValueRange;
    private:
        Value       first_;
        Index       i_;

        It( Value const first, Index const i )
            : first_( first )
            , i_( i )
        {}

    public:
        void operator++()           { ++i_; }
        Value operator*() const     { return first_ + i_; }

        bool operator!=( It const& other ) const
        { assert( first_ == other.first_ );  return (i_ != other.i_); }

        bool operator<( It const& other ) const
        { assert( first_ == other.first_ );  return (i_ < other.i_); }
    };

    Value first() const     { return first_; }
    Value last() const      { return first_ + span_; }

    It begin() const        { return It( first_, 0 ); }
    It end() const          { return It( first_, span_ + 1 ); }

    ValueRange( Value const first, Value const last )
        : first_( first )
        , span_( Size( last - first ) )
    {
        assert( first_ + span_ == last );
    }
};

#include <algorithm>    // std::for_each
#include <iostream>     // std::wcout, std::endl

int main()
{
    using namespace std;

    ValueRange< double > const   r( 1.0, 6.0 );

    for_each( r.begin(), r.end(), []( double x )
    {
        using std::wcout;       // For Visual C++ 10.0.
        wcout << x << " ";
    } );
    wcout << endl;
}
于 2012-05-27T03:20:46.303 回答