Forward Iterator C ++:for_each行为

时间:2012-05-26 23:21:29

标签: c++ foreach iterator forward

所以我们知道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;
}

它进入无限循环,因为第一个“!=”last(它不是第一个“&lt;”last),所以人们在实现自己的前向迭代器以使用for_each时如何做?

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

无论如何你想要实现什么......你的班级是否有任何内部存储空间,或者它只是数字序列的代表?

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

如果您的班级有内部存储空间,那么您的指针应该有指向它的指针(T* pData_;而不是T pData_;),然后您就不需要移除T &operator*() 中的星标了对于正确的版本;)重点是增量迭代器应该递增此指针,并且add1函数中的递增值应该增加指向值。现在两个操作都会增加相同的变量,因此您可以获得+=2

编辑:

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

唯一的选择是在任何地方用const_iterator替换迭代器,以便不能修改迭代值。现在这有点反对ISO C ++,它将容器划分为几个类别,对于每个类别,仅当容器本身被声明为begin()时,它才需要end()const_iterator才能返回const 。但是我觉得最多可以说Range类在ISO C ++视图中是偶数容器,因为(根据23.1.1)

  

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

Sice在Range类中似乎没有任何实际存储的迭代对象,我认为我们在这里是非常野蛮的,并且不需要那么多符合标准。

EDIT2:

首先const iteratorconst_iterator不同。第一个是无法更改的迭代器(指向序列中的不同值,例如递增),另一个允许,但不允许更改指向值,因此(*i)=3将失败。 / p>

其次,我就是这样做的:

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(或者使用qqwfmnghng作为类名),只要你遵守const_iterator规范 - 在这种情况下不提供l值运算符,因为那些意图修改指向价值 - 会有什么意义?

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