第5章:イテレータとユーティリティ

はじめに

イテレータはSTLの中核概念です。本章では、iterator_traits、reverse_iterator、そして各種ユーティリティを学びます。

---

1. iterator_traits

1.1 なぜtraitsが必要か

テンプレートでイテレータを扱う際、その型情報が必要になります:

template<typename Iterator>
void algorithm(Iterator first, Iterator last) {
    // Iteratorが指す型は?
    // difference_typeは?
    // イテレータカテゴリは?
}

1.2 実装

namespace ft {

// プライマリテンプレート(クラスイテレータ用)
template<typename Iterator>
struct iterator_traits {
    typedef typename Iterator::difference_type   difference_type;
    typedef typename Iterator::value_type        value_type;
    typedef typename Iterator::pointer           pointer;
    typedef typename Iterator::reference         reference;
    typedef typename Iterator::iterator_category iterator_category;
};

// ポインタの特殊化
template<typename T>
struct iterator_traits<T*> {
    typedef ptrdiff_t                       difference_type;
    typedef T                               value_type;
    typedef T*                              pointer;
    typedef T&                              reference;
    typedef std::random_access_iterator_tag iterator_category;
};

// constポインタの特殊化
template<typename T>
struct iterator_traits<const T*> {
    typedef ptrdiff_t                       difference_type;
    typedef T                               value_type;
    typedef const T*                        pointer;
    typedef const T&                        reference;
    typedef std::random_access_iterator_tag iterator_category;
};

} // namespace ft

1.3 使用例

template<typename Iterator>
typename ft::iterator_traits<Iterator>::difference_type
distance(Iterator first, Iterator last) {
    typedef typename ft::iterator_traits<Iterator>::iterator_category category;
    return _distance_impl(first, last, category());
}

// RandomAccessIterator用(O(1))
template<typename Iterator>
typename ft::iterator_traits<Iterator>::difference_type
_distance_impl(Iterator first, Iterator last,
               std::random_access_iterator_tag) {
    return last - first;
}

// InputIterator用(O(n))
template<typename Iterator>
typename ft::iterator_traits<Iterator>::difference_type
_distance_impl(Iterator first, Iterator last,
               std::input_iterator_tag) {
    typename ft::iterator_traits<Iterator>::difference_type n = 0;
    while (first != last) {
        ++first;
        ++n;
    }
    return n;
}

---

2. reverse_iterator

2.1 概念

reverse_iteratorは、イテレータを逆順に走査します:

通常のイテレータ:
[1] → [2] → [3] → [4] → end

reverse_iterator:
rbegin ← [4] ← [3] ← [2] ← [1] ← rend

注意: rbegin() は end() の位置を指し、
      *rbegin() は最後の要素を返す

2.2 実装

namespace ft {

template<typename Iterator>
class reverse_iterator {
public:
    typedef Iterator                                              iterator_type;
    typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
    typedef typename iterator_traits<Iterator>::value_type        value_type;
    typedef typename iterator_traits<Iterator>::difference_type   difference_type;
    typedef typename iterator_traits<Iterator>::pointer           pointer;
    typedef typename iterator_traits<Iterator>::reference         reference;

protected:
    Iterator current;

public:
    // コンストラクタ
    reverse_iterator() : current() {}

    explicit reverse_iterator(iterator_type x) : current(x) {}

    template<typename Iter>
    reverse_iterator(const reverse_iterator<Iter>& other)
        : current(other.base()) {}

    // 基底イテレータを取得
    iterator_type base() const {
        return current;
    }

    // 間接参照(1つ前の要素を返す)
    reference operator*() const {
        Iterator tmp = current;
        return *--tmp;
    }

    pointer operator->() const {
        return &(operator*());
    }

    // インクリメント(基底イテレータをデクリメント)
    reverse_iterator& operator++() {
        --current;
        return *this;
    }

    reverse_iterator operator++(int) {
        reverse_iterator tmp = *this;
        --current;
        return tmp;
    }

    // デクリメント(基底イテレータをインクリメント)
    reverse_iterator& operator--() {
        ++current;
        return *this;
    }

    reverse_iterator operator--(int) {
        reverse_iterator tmp = *this;
        ++current;
        return tmp;
    }

    // ランダムアクセス
    reverse_iterator operator+(difference_type n) const {
        return reverse_iterator(current - n);
    }

    reverse_iterator& operator+=(difference_type n) {
        current -= n;
        return *this;
    }

    reverse_iterator operator-(difference_type n) const {
        return reverse_iterator(current + n);
    }

    reverse_iterator& operator-=(difference_type n) {
        current += n;
        return *this;
    }

    reference operator[](difference_type n) const {
        return *(*this + n);
    }
};

// 比較演算子
template<typename Iterator1, typename Iterator2>
bool operator==(const reverse_iterator<Iterator1>& lhs,
                const reverse_iterator<Iterator2>& rhs) {
    return lhs.base() == rhs.base();
}

template<typename Iterator1, typename Iterator2>
bool operator!=(const reverse_iterator<Iterator1>& lhs,
                const reverse_iterator<Iterator2>& rhs) {
    return lhs.base() != rhs.base();
}

template<typename Iterator1, typename Iterator2>
bool operator<(const reverse_iterator<Iterator1>& lhs,
               const reverse_iterator<Iterator2>& rhs) {
    return lhs.base() > rhs.base();  // 逆順なので逆の比較
}

// ... 他の比較演算子 ...

// 算術演算子
template<typename Iterator>
reverse_iterator<Iterator>
operator+(typename reverse_iterator<Iterator>::difference_type n,
          const reverse_iterator<Iterator>& it) {
    return reverse_iterator<Iterator>(it.base() - n);
}

template<typename Iterator1, typename Iterator2>
typename reverse_iterator<Iterator1>::difference_type
operator-(const reverse_iterator<Iterator1>& lhs,
          const reverse_iterator<Iterator2>& rhs) {
    return rhs.base() - lhs.base();
}

} // namespace ft

---

3. enable_if

3.1 SFINAEとは

SFINAE = "Substitution Failure Is Not An Error"

テンプレート引数の置換に失敗しても、コンパイルエラーにならず、そのオーバーロード候補から除外されます。

3.2 実装

namespace ft {

// プライマリテンプレート(条件がfalseの場合)
template<bool Cond, typename T = void>
struct enable_if {};

// 特殊化(条件がtrueの場合)
template<typename T>
struct enable_if<true, T> {
    typedef T type;
};

} // namespace ft

3.3 使用例

// 整数型の場合のみ有効な関数
template<typename T>
typename ft::enable_if<ft::is_integral<T>::value, bool>::type
is_odd(T val) {
    return val % 2 == 1;
}

// vectorのrangeコンストラクタで使用
template<typename T, typename Alloc>
template<typename InputIterator>
vector<T, Alloc>::vector(
    InputIterator first,
    InputIterator last,
    const allocator_type& alloc,
    typename ft::enable_if<!ft::is_integral<InputIterator>::value>::type*
) : _alloc(alloc), _data(NULL), _size(0), _capacity(0) {
    // 本当のイテレータの場合の処理
}

---

4. is_integral

4.1 実装

namespace ft {

// デフォルト(非整数型)
template<typename T>
struct is_integral {
    static const bool value = false;
    typedef bool value_type;
    typedef is_integral type;
};

// 各整数型の特殊化
template<> struct is_integral<bool>               { static const bool value = true; };
template<> struct is_integral<char>               { static const bool value = true; };
template<> struct is_integral<signed char>        { static const bool value = true; };
template<> struct is_integral<unsigned char>      { static const bool value = true; };
template<> struct is_integral<wchar_t>            { static const bool value = true; };
template<> struct is_integral<short>              { static const bool value = true; };
template<> struct is_integral<unsigned short>     { static const bool value = true; };
template<> struct is_integral<int>                { static const bool value = true; };
template<> struct is_integral<unsigned int>       { static const bool value = true; };
template<> struct is_integral<long>               { static const bool value = true; };
template<> struct is_integral<unsigned long>      { static const bool value = true; };
template<> struct is_integral<long long>          { static const bool value = true; };
template<> struct is_integral<unsigned long long> { static const bool value = true; };

// const/volatile修飾子を除去
template<typename T> struct is_integral<const T>
    : is_integral<T> {};
template<typename T> struct is_integral<volatile T>
    : is_integral<T> {};
template<typename T> struct is_integral<const volatile T>
    : is_integral<T> {};

} // namespace ft

---

5. pair と make_pair

5.1 pair

namespace ft {

template<typename T1, typename T2>
struct pair {
    typedef T1 first_type;
    typedef T2 second_type;

    T1 first;
    T2 second;

    // コンストラクタ
    pair() : first(), second() {}

    pair(const T1& a, const T2& b) : first(a), second(b) {}

    template<typename U1, typename U2>
    pair(const pair<U1, U2>& p) : first(p.first), second(p.second) {}

    // 代入演算子
    pair& operator=(const pair& p) {
        first = p.first;
        second = p.second;
        return *this;
    }
};

// 比較演算子
template<typename T1, typename T2>
bool operator==(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs) {
    return lhs.first == rhs.first && lhs.second == rhs.second;
}

template<typename T1, typename T2>
bool operator!=(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs) {
    return !(lhs == rhs);
}

template<typename T1, typename T2>
bool operator<(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs) {
    return lhs.first < rhs.first ||
           (!(rhs.first < lhs.first) && lhs.second < rhs.second);
}

template<typename T1, typename T2>
bool operator<=(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs) {
    return !(rhs < lhs);
}

template<typename T1, typename T2>
bool operator>(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs) {
    return rhs < lhs;
}

template<typename T1, typename T2>
bool operator>=(const pair<T1, T2>& lhs, const pair<T1, T2>& rhs) {
    return !(lhs < rhs);
}

} // namespace ft

5.2 make_pair

namespace ft {

template<typename T1, typename T2>
pair<T1, T2> make_pair(T1 x, T2 y) {
    return pair<T1, T2>(x, y);
}

} // namespace ft

---

6. equal と lexicographical_compare

6.1 equal

namespace ft {

// バージョン1: デフォルト比較
template<typename InputIterator1, typename InputIterator2>
bool equal(InputIterator1 first1, InputIterator1 last1,
           InputIterator2 first2) {
    while (first1 != last1) {
        if (!(*first1 == *first2))
            return false;
        ++first1;
        ++first2;
    }
    return true;
}

// バージョン2: カスタム比較関数
template<typename InputIterator1, typename InputIterator2,
         typename BinaryPredicate>
bool equal(InputIterator1 first1, InputIterator1 last1,
           InputIterator2 first2, BinaryPredicate pred) {
    while (first1 != last1) {
        if (!pred(*first1, *first2))
            return false;
        ++first1;
        ++first2;
    }
    return true;
}

} // namespace ft

6.2 lexicographical_compare

辞書順比較:

namespace ft {

// バージョン1: デフォルト比較
template<typename InputIterator1, typename InputIterator2>
bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1,
                             InputIterator2 first2, InputIterator2 last2) {
    while (first1 != last1) {
        if (first2 == last2 || *first2 < *first1)
            return false;
        else if (*first1 < *first2)
            return true;
        ++first1;
        ++first2;
    }
    return first2 != last2;
}

// バージョン2: カスタム比較関数
template<typename InputIterator1, typename InputIterator2, typename Compare>
bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1,
                             InputIterator2 first2, InputIterator2 last2,
                             Compare comp) {
    while (first1 != last1) {
        if (first2 == last2 || comp(*first2, *first1))
            return false;
        else if (comp(*first1, *first2))
            return true;
        ++first1;
        ++first2;
    }
    return first2 != last2;
}

} // namespace ft

---

7. イテレータカテゴリ

7.1 カテゴリタグ

// STL標準のタグ(<iterator>で定義)
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

7.2 カテゴリによるディスパッチ

template<typename Iterator>
void advance(Iterator& it,
             typename ft::iterator_traits<Iterator>::difference_type n) {
    typedef typename ft::iterator_traits<Iterator>::iterator_category category;
    _advance_impl(it, n, category());
}

// RandomAccessIterator用
template<typename Iterator>
void _advance_impl(Iterator& it,
                   typename ft::iterator_traits<Iterator>::difference_type n,
                   std::random_access_iterator_tag) {
    it += n;
}

// BidirectionalIterator用
template<typename Iterator>
void _advance_impl(Iterator& it,
                   typename ft::iterator_traits<Iterator>::difference_type n,
                   std::bidirectional_iterator_tag) {
    if (n >= 0) {
        while (n--) ++it;
    } else {
        while (n++) --it;
    }
}

// InputIterator用
template<typename Iterator>
void _advance_impl(Iterator& it,
                   typename ft::iterator_traits<Iterator>::difference_type n,
                   std::input_iterator_tag) {
    while (n--) ++it;
}

---

まとめ

本章で学んだこと:

  • iterator_traits: イテレータの型情報を取得
  • reverse_iterator: 逆順走査
  • enable_if: SFINAEによる条件付きオーバーロード
  • is_integral: 整数型判定
  • pair/make_pair: 2つの値のペア
  • equal/lexicographical_compare: 範囲の比較

次章では、テストと最適化を学びます。