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;
}

first "!=" last (first"<"last ではない) が原因で無限ループに入るので、 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()返されます。ただし、(23.1.1によると)クラスがISOC++ビューのコンテナでさえあることはせいぜい議論の余地があると思います。const_iteratorconstRange

コンテナは、他のオブジェクトを格納するオブジェクトです。これらは、コンストラクタ、デストラクタ、挿入および消去操作を通じて、これらのオブジェクトの割り当てと割り当て解除を制御します。

Rangeクラスには、反復オブジェクトの実際のストレージがないようです。ここでは、私たちは野外に出ており、標準にそれほど準拠する必要はないと思います。

EDIT2:

まず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を使用する)ことは明らかに自由です-この場合、指定された値を変更することを目的としているため、l値演算子を提供しません-何それは意味がありますか?

于 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 に答える