C++カスタム反復器

6986 ワード

例では、単純な反復器タイプの定義を見てみましょう.数値タイプの値を表すクラステンプレートを定義します.また、指定した範囲の開始および終了反復器を生成することもできます.この反復器もテンプレートタイプで、両方のテンプレートは同じヘッダファイルNumeric_に定義されています.Range.h中.次はNumeric_Rangeテンプレートの定義:
template  class Numeric_Iterator;    // Template type declaration
// Defines a numeric range
template
class Numeric_Range
{
    static_assert(std::is_integral::value || std::is_floating_point::value,
                                 "Numeric_Range type argument must be numeric.");
    friend class Numeric_Iterator < T >;
protected:
    T start;                                       // First value in the range
    T step;                                        // Increment between successive values
    size_t count;                                  // Number of values in the range
public:
    Numeric_Range(T first=0, T incr=1, size_t n=2) : start {first}, step {incr}, count {n}{}
    // Return the begin iterator for the range
    Numeric_Iterator begin(){ return Numeric_Iterator(*this); }
    // Return the end iterator for the range
    Numeric_Iterator end()
    {
        Numeric_Iterator end_iter(*this);
        end_iter.value = start + count*step;          // End iterator value is one step over the last
        return end_iter;
    }
};

タイプパラメータTはシーケンスの値タイプであるため、必ず数値タイプである.テンプレート本体の関数static_の場合assert()は、Tが整数型でも浮動小数点型でもない場合、最初のパラメータがfalseになり、2番目の文字列パラメータを含むコンパイル時のエラーメッセージが生成されます.ここで使用するブレークスルーテンプレートは、ヘッダファイルtype_に定義されます.traitsでは、テンプレートに他のコンパイル時にテンプレートタイプパラメータが断言をチェックするものもあります.このコンストラクション関数の3つのパラメータにはデフォルト値があるため、無パラメトリックコンストラクション関数としても使用できます.この3つのパラメータは、それぞれ値を初期化し、1つの値から別の値への増分を指定し、値の数を指定するために使用されます.したがって、デフォルトでは、0と1の2つの値を持つ要素セグメントが定義されています.コンパイラは、必要に応じて適切なコピーコンストラクタを提供します.
2つのメンバー関数が生成され、要素セグメントの開始と終了反復器が返されます.反復器を終了するメンバー変数valueの値は、最後のvalue+1です.終了反復器は、開始反復器のvalueを変更することによって生成されます.Numeric_Itemtorテンプレートタイプの宣言は、反復器タイプテンプレートが定義されていないため、定義する前に必要です.Numeric_Iteratorテンプレートはこのテンプレートの友元クラスとして指定され、Numeric_IteratorのインスタンスはNumeric_にアクセスできます.Rangeのプライベートメンバー.Numeric_RangeテンプレートもNumeric_になる必要がありますNumeric_Rangeのメンバー関数end()にアクセスするにはNumeric_Iteratorのプライベートメンバーです.
この反復器のテンプレートタイプは次のように定義されます.
// Iterator class template- it's a forward iterator
template
class Numeric_Iterator : public std::iterator < std::forward_iterator_tag, T >
{
    friend class Numeric_Range < T >;
protected:
    Numeric_Range& range;                       // Reference to the range for this iterator
    T value;                                       // Value pointed to
public:
    explicit Numeric_Iterator(Numeric_Range& a_range) : range {a_range}, value {a_range.start} {};

    // Assignment operator
    Numeric_Iterator& operator=(const Numeric_Iterator& src)
    {
        range = src.range;
        value = src.value;
    }

    // Dereference an iterator
    T& operator*()
    {
        // When the value is one step more than the last, it's an end iterator
        if (value == static_cast(range.start + range.count*range.step))
        {
            throw std::logic_error("Cannot dereference an end iterator.");
        }
        return value;
    }

    // Prefix increment operator
    Numeric_Iterator& operator++()
    {
        // When the value is one step more than the last, it's an end iterator
        if (value == static_cast(range.start + range.count*range.step))
        {
            throw std::logic_error("Cannot increment an end iterator.");
        }
        value += range.step;                         // Increment the value by the range step
        return *this;
    }

    // Postfix increment operator
    Numeric_Iterator operator++(int)
    {
        // When the value is one step more than the last, it's an end iterator
        if (value == static_cast(range.start + range.count*range.step))
        {
            throw std::logic_error("Cannot increment an end iterator.");
        }
        auto temp = *this;
        value += range.step;                         // Increment the value by the range step
        return temp;                                 // The iterator before it's incremented
    }

    // Comparisons
    bool operator(const Numeric_Iterator& iter) const { return value > iter.value; }
    bool operator<=(const Numeric_Iterator& iter) const { *this < iter || *this == iter; }
    bool operator>=(const Numeric_Iterator& iter) const { *this > iter || *this == iter; }
};

コードは多いように見えますが、簡単にわかります.この反復器にはメンバー変数があり、それに関連付けられたNumeric_が保存されています.Rangeオブジェクトの参照は、要素を指す値も保存されます.反復器の構造関数のパラメータはNumeric_です.Rangeオブジェクトの参照.コンストラクション関数はパラメータでメンバー変数rangeを初期化し、メンバー変数valueの値をNumeric_に設定します.Rangeのstart.
また、いくつかの逆参照演算子、接頭辞または接尾辞の自己増加演算子、および比較演算子も定義されています.要素セグメントのエンド反復器の解参照または自己増加は不正であるため、オペランドがエンド反復器である場合、自己増加演算子関数と解参照演算子関数は例外を放出します.これは、メンバー変数valueが要素セグメントの最後の値を超えていることを示します.簡単にするために、標準例外を放出することを選択します.
プライマリファイルNumeric_Range.cの完全な内容は以下の通りである.
// Exercising the Numeric_Range template
#include  // For copy()
#include  // For accumulate()
#include  // For standard streams
#include  // For vector container
#include "Numeric_Range.h" // For Numeric_Range & Numeric_Iterator

int main()
{
    Numeric_Range range {1.5, 0.5, 5};
    auto first = range.begin();
    auto last = range.end();
    std::copy(first, last, std::ostream_iterator(std::cout, "  "));
    std::cout << "
Sum = " << std::accumulate(std::begin(range), std::end(range), 0.0) << std::endl; // Initializing a container from a Numeric_Range Numeric_Range numbers {15L, 4L, 10}; std::vector data {std::begin(numbers), std::end(numbers)}; std::cout << "
Values in vector are:
"; std::copy(std::begin(data), std::end(data), std::ostream_iterator(std::cout, " ")); std::cout << std::endl; // List the values in a range std::cout << "
The values in the numbers range are:
"; for (auto n : numbers) std::cout << n << " "; std::cout << std::endl; }

運転結果:1.5 2 2.5 3 3.5 Sum=12.5 Values in vectorare:15 19 23 27 31 35 39 43 47 51 The values in the numbers range are:15 19 23 27 31 35 39 43 47 51
生成された最初のNumeric_Rangeインスタンスには、1.5から0.5ずつ増加する5つのdouble型要素があります.Numeric_Rangeの反復器はcopy()アルゴリズムで値をostream_にコピーするために使用されます.iterator.これはアルゴリズムがこの反復器を受け入れることができることを示している.2番目のNumeric_Rangeインスタンスには10個のlong型要素があります.vectorコンテナの初期化リストで、反復器の開始と終了を使用し、vectorの要素をcopy()アルゴリズムで出力します.最後に,その動作原理を実証するためにforサイクルでその値を出力する.出力表示Numeric_Rangeテンプレートは整数型と浮動小数点型の要素セグメントの作成に成功し,STLを使用できる反復器タイプを定義することに成功した.