Custom iterators in c++

I have a collection of object of type "T" that i want to iterate through. An object of type "T" has two important properties:

int r; // row number
int c; // column number

I would like to define an iterator that allows me to iterate through all elements of the collection.

This can be done using:

std::vector<T> v;

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
....
}

However, I would like the iterator to have one more property. I would like to be able to call

it.nextrow()

calling this function should return the element "e" of v where e.r + 1 = ec.r and e.c = ec.c, where ec is the current element pointed by the iterator. I.e. calling it.nextrow() should give me a pointer to the element where column is the same, but row is incremented by one. Hope it makes sense.

I am not sure what I need to do in order for this to work, as I am fairly new to advanced c++ concepts. Can anybody help me?



Something along these lines, perhaps:

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
#include <iostream>
#include <vector>
#include <iterator>

template < typename T > struct collection
{
    collection( std::size_t nrows, std::size_t ncols, const T& v = {} )
        : nrows(nrows), ncols(ncols), items( nrows*ncols, v ) {}

    struct iterator
    {
        using value_type = T ;
        using reference = T& ;
        using pointer = T* ;
        using difference_type = std::ptrdiff_t ;
        using iterator_category	= std::forward_iterator_tag ;

        reference operator* () { return *curr ; }
        // pointer operator& () { return &**this ; }
        pointer operator-> () { return &**this ; } // *** EDIT

        iterator& operator++ () { ++curr ; return *this ; }
        iterator operator++ (int) { const auto temp(*this) ; ++*this ; return temp ; }

        bool operator== ( const iterator& that ) const { return curr == that.curr ; }
        bool operator!= ( const iterator& that ) const { return !(*this==that) ; }

        iterator& next_row()
        {
            if( std::distance( curr, end ) >= difference_type(ncols) ) std::advance( curr, ncols ) ;
            else curr = end ;
            return *this ;
        }

        typename std::vector<T>::iterator curr ;
        typename std::vector<T>::iterator end ;
        std::size_t ncols ;

    };

    iterator begin() { return { std::begin(items), std::end(items), ncols } ; }
    iterator end() { return { std::end(items), std::end(items), ncols } ; }

    std::size_t nrows ;
    std::size_t ncols ;
    std::vector<T> items ;
};

int main()
{
    collection<int> coll( 10, 12 ) ;

    int n = 0 ;
    for( int& v : coll ) v = n++ ;



    // print column #3
    for( auto iter = ++++++std::begin(coll) ; iter != std::end(coll) ; iter.next_row() )
        std::cout << *iter << ' ' ;
    std::cout << '\n' ;

    // print column #5
    for( auto iter = std::next( std::begin(coll), 5 ) ; iter != std::end(coll) ; iter.next_row() )
        std::cout << *iter << ' ' ;
    std::cout << '\n' ;

    // print column #11 (the last column)
    for( auto iter = std::next( std::begin(coll), 11 ) ; iter != std::end(coll) ; iter.next_row() )
        std::cout << *iter << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/bef1bc658a91d7d4
http://rextester.com/NVW58875
Last edited on
Thanks. I need begin() and end() to be const functions, but this does not work with the proposed code. Can you help me?
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
#include <iostream>
#include <vector>
#include <iterator>

template < typename T > struct collection
{
    collection( std::size_t nrows, std::size_t ncols, const T& v = {} )
        : nrows(nrows), ncols(ncols), items( nrows*ncols, v ) {}

    struct const_iterator
    {
        using value_type = const T ;
        using reference = const T& ;
        using pointer = const T* ;
        using difference_type = std::ptrdiff_t ;
        using iterator_category	= std::forward_iterator_tag ;

        reference operator* () { return *curr ; }
        pointer operator-> () { return &**this ; }

        const_iterator& operator++ () { ++curr ; return *this ; }
        const_iterator operator++ (int) { const auto temp(*this) ; ++*this ; return temp ; }

        bool operator== ( const const_iterator& that ) const { return curr == that.curr ; }
        bool operator!= ( const const_iterator& that ) const { return !(*this==that) ; }

        const_iterator& next_row()
        {
            if( std::distance( curr, end ) >= difference_type(ncols) ) std::advance( curr, ncols ) ;
            else curr = end ;
            return *this ;
        }

        typename std::vector<T>::const_iterator curr ;
        typename std::vector<T>::const_iterator end ;
        std::size_t ncols ;
    };

    const_iterator begin() const { return { std::begin(items), std::end(items), ncols } ; }
    const_iterator end() const { return { std::end(items), std::end(items), ncols } ; }

    std::size_t nrows ;
    std::size_t ncols ;
    std::vector<T> items ;
};

int main()
{
    collection<int> coll( 10, 12 ) ;

    int n = 0 ;
    for( int& v : coll.items ) v = n++ ;

    // print column #3
    for( auto iter = ++++++std::begin(coll) ; iter != std::end(coll) ; iter.next_row() )
        std::cout << *iter << ' ' ;
    std::cout << '\n' ;

    // print column #5
    for( auto iter = std::next( std::begin(coll), 5 ) ; iter != std::end(coll) ; iter.next_row() )
        std::cout << *iter << ' ' ;
    std::cout << '\n' ;

    // print column #11 (the last column)
    for( auto iter = std::next( std::begin(coll), 11 ) ; iter != std::end(coll) ; iter.next_row() )
        std::cout << *iter << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/570019c922d7ecd2
http://rextester.com/DXEL3784
I would suggest not to use a custom iterator. Instead you may have a [free] function that uses find_if(...) in order to return the appropriate iterator. See:

http://www.cplusplus.com/reference/algorithm/find_if/?kw=find_if
Topic archived. No new replies allowed.