0%

C++11 range-based for loops for custom container

在C++11中,可以這樣用已經不是什麼新鮮事了。

1
2
3
4
5
vector<int> vec;
for (int i : vec )
{
cout << i << endl;
}

如果要在自己的container支援這特性的話,需滿足以下條件。

  • Container必須擁有beginend函數,這兩個函數必須回傳一個 Iterator
  • Iterator必須擁有*++ (prefix版)!=這三個operator function。
    以下範例是從C++11 range-based for loops修改而來,加上自己的實驗。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    #include <iostream>
    #include <algorithm>
    using namespace std;
    class IntVector;

    class ConstIter
    {
    public:
    ConstIter(const IntVector* p_vec, int pos)
    : _pos(pos)
    , _p_vec(p_vec)
    { }
    bool operator!= (const ConstIter& other) const
    {
    return _pos != other._pos;
    }
    int operator* () const;
    const ConstIter& operator++ ()
    {
    ++_pos;
    return *this;
    }
    private:
    int _pos;
    const IntVector *_p_vec;
    };

    class Iter
    {
    public:
    Iter(IntVector* p_vec, int pos) : _pos(pos) , _p_vec(p_vec) { }
    bool operator!= (const Iter& other) const
    {
    return _pos != other._pos;
    }
    int& operator* ();
    Iter& operator++ ()
    {
    ++_pos;
    return *this;
    }
    private:
    int _pos;
    IntVector *_p_vec;
    };

    class IntVector
    {
    public:
    int get(int col) const { return _data[col]; }
    int& get(int col) { return _data[col]; }

    IntVector() {}



    Iter begin()
    {
    return Iter(this, 0);
    }

    Iter end()
    {
    return Iter(this, 100);
    }

    ConstIter begin() const
    {
    return ConstIter(this, 0);
    }
    ConstIter end() const
    {
    return ConstIter(this, 100);
    }

    void set(int index, int val)
    {
    _data[index] = val;
    }

    private:
    int _data[100];
    };

    int
    ConstIter::operator* () const
    {
    return _p_vec->get(_pos);
    }

    int&
    Iter::operator* ()
    {
    return _p_vec->get(_pos);
    }

    int main()
    {
    IntVector v;
    for (int i = 0; i < 100; i++)
    v.set(i, i);
    transform(v.begin(), v.end(), v.begin(), [](int v) { return v * 2; });
    for (int& i : v) { i *= 2; }
    for (const int& i : v) { cout << i << endl; }
    }
    在gcc跟clang都能正常運作,不過到了VC12 Debug Mode就編譯失敗了。
    這是由於Checked Iterator這巷特性。
    最快的解決方案是在前面加上
    1
    2
    3
    4
    5
    6
    #ifndef _ITERATOR_DEBUG_LEVEL
    #define _ITERATOR_DEBUG_LEVEL 0
    #else
    #undef _ITERATOR_DEBUG_LEVEL
    #define _ITERATOR_DEBUG_LEVEL 0
    #endif