所以我们知道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时如何做?
答案 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 iterator
与const_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;
}