Chapter 18 Section 18.3.1 Copy constructor help needed in compiling

Pages: 12
> I don't know how to define custom iterators.
>> defining iterators and iterator_traits is completely new to me.
>> I'm also not at the place in the book where it talks about that yet.

A raw pointer to an element in an array is a random access iterator. For a simple iterator for a toy vector, just alias a pointer for the iterator.

For example:

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <iostream>
#include <iterator>
#include <initializer_list>
#include <new>
#include <algorithm>
#include <stdexcept>
#include <cmath>
#include <type_traits>

namespace toy
{
    // a very simplified vector of doubles (like vector<double>)
    struct vector
    {
        using value_type = double ;
        using size_type = std::size_t ;
        using pointer = value_type* ;
        using const_pointer = const value_type* ;
        using reference = value_type& ;
        using const_reference = const value_type& ;
        using iterator = pointer ;
        using const_iterator = const_pointer ;
        // http://en.cppreference.com/w/cpp/iterator/reverse_iterator
        using reverse_iterator = std::reverse_iterator<iterator> ;
        using const_reverse_iterator = std::reverse_iterator<const_iterator> ;
        static_assert( std::is_trivially_destructible<value_type>::value, "destructors are not called" ) ;

        // constructors
        vector() noexcept = default ;
        vector( size_type n, const value_type& v = {} ) { while( size() < n ) push_back(v) ; }
        vector( std::initializer_list<value_type> il ) { for( const auto& v : il ) push_back(v) ; }
        template < typename ITERATOR > vector( ITERATOR begin, ITERATOR end )
        { for( ; begin != end ; ++begin ) push_back(*begin) ; }

        // copy and move constructors
        vector( const vector& that ) { for( const auto& v : that ) push_back(v) ; }
        vector( vector&& that ) noexcept { swap(that) ; }

        // lazy: unifying assignment operator
        vector& operator= ( vector that ) noexcept { return swap(that) ; }

        ~vector() { clear() ; deallocate(arr); }

        bool empty() const noexcept { return size() == 0 ; }
        size_type size() const noexcept { return sz ; }

        iterator begin() noexcept { return arr ; }
        iterator end() noexcept { return arr ? arr+size() : nullptr ; }
        const_iterator begin() const noexcept { return arr ; }
        const_iterator end() const noexcept { return arr ? arr+sz : nullptr ; }
        const_iterator cbegin() const noexcept { return begin() ; }
        const_iterator cend() const noexcept { return end() ; }

        reverse_iterator rbegin() { return reverse_iterator{ end() } ; }
        reverse_iterator rend() { return reverse_iterator{ begin() } ; }
        const_reverse_iterator rbegin() const { return const_reverse_iterator{ end() } ; }
        const_reverse_iterator rend() const { return const_reverse_iterator{ begin() } ; }
        const_reverse_iterator crbegin() const { return rbegin() ; }
        const_reverse_iterator crend() const { return rend() ; }

        reference front() { return begin()[0] ; }
        const_reference front() const { return begin()[0] ; }
        reference back() { return rbegin()[0] ; }
        const_reference back() const { return rbegin()[0] ; }

        reference operator[] ( size_type pos ) noexcept { return begin()[pos] ; }
        const_reference operator[] ( size_type pos ) const noexcept { return begin()[pos] ; }

        reference at( size_type pos )
        {
            if( pos >= size() ) throw std::out_of_range( "toy::vector: out of range" ) ;
            return begin()[pos] ;
        }
        const_reference at( size_type pos ) const
        {
            if( pos >= size() ) throw std::out_of_range( "toy::vector: out of range" ) ;
            return begin()[pos] ;
        }

        void push_back( const value_type& v )
        {
            reserve( size()+1 ) ;
            new ( arr + sz ) value_type(v) ;
            ++sz ;
        }

        void pop_back() noexcept { --sz ; }

        void clear() { resize(0) ; }
        void resize( size_type n, const value_type& v = {} )
        {
            while( size() < n ) push_back(v) ;
            while( size() > n ) pop_back() ;
        }

        vector& swap( vector& that ) noexcept
        {
            using std::swap ;
            swap( arr, that.arr ) ;
            swap( sz, that.sz ) ;
            swap( cap, that.cap ) ;
            return *this ;
        }

        size_type capacity() const noexcept { return cap ; }
        void reserve( size_type new_cap )
        {
            if( new_cap <= cap ) return ;

            new_cap = std::max( { size_type(16), sz*2, new_cap } ) ;
            const auto ptr = allocate(new_cap) ;
            std::copy( begin(), end(), ptr ) ;
            cap = new_cap ;
            deallocate(arr) ;
            arr = ptr ;
        }

        // overloaded compound assignment operator
        template < typename T >
        typename std::enable_if< std::is_arithmetic<T>::value, vector& >::type operator+= ( T v )
        { for( auto& value : *this ) value += v ; return *this ; }

        template < typename T >
        typename std::enable_if< std::is_arithmetic<T>::value, vector& >::type operator-= ( T v )
        { for( auto& value : *this ) value -= v ; return *this ; }

        template < typename T >
        typename std::enable_if< std::is_arithmetic<T>::value, vector& >::type operator*= ( T v )
        { for( auto& value : *this ) value *= v ; return *this ; }

        template < typename T >
        typename std::enable_if< std::is_arithmetic<T>::value, vector& >::type operator/= ( T v )
        { for( auto& value : *this ) value /= v ; return *this ;  }

        private:
            value_type* arr = nullptr ;
            size_type sz = 0 ;
            size_type cap = 0 ;

            static pointer allocate( size_type n )
            { return pointer( ::operator new[] ( n * sizeof(value_type) ) ) ; }

            static void deallocate( pointer p ) { ::operator delete[] (p) ; }
    };
}
Continued
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
namespace toy 
{
    void swap( vector& a, vector& b ) { a.swap(b) ; }

    // "comparing two floating-point numbers is harder than it looks
    // if your goal is to meet the C++ order-relation requirements.
    // The most straightforward strategy for defining comparison on
    // floating-point numbers that might include NaN is to decide
    // either that every NaN is "less than" every other number
    // or "greater than" every other number." - Koenig
    namespace detail
    {
        struct less
        {
            bool operator() ( double a, double b ) const noexcept
            {
                if( std::isnan(b) ) return !std::isnan(a);
                else return a < b ; // crude (to be refined)
            }
        };

        struct eq
        {
            bool operator() ( double a, double b ) const noexcept
            {
                if( std::isnan(a) ) return std::isnan(b);
                else return a == b ; // crude (to be refined)
            }
        };
    }

    bool operator== ( const vector& a, const vector& b ) noexcept
    { return std::equal( a.begin(), a.end(), b.begin(), b.end(), detail::eq{} ) ; }

    bool operator< ( const vector& a, const vector& b ) noexcept
    { return std::lexicographical_compare( a.begin(), a.end(), b.begin(), b.end(), detail::less{} ) ; }

    bool operator!= ( const vector& a, const vector& b ) noexcept { return !(a==b) ; }
    bool operator> ( const vector& a, const vector& b ) noexcept { return b<a ; }
    bool operator<= ( const vector& a, const vector& b ) noexcept { return !(b<a) ; }
    bool operator>= ( const vector& a, const vector& b ) noexcept { return !(a<b) ; }

    // canonical overloads of binary arithmetic operators
    // see 'Binary arithmetic operators' in http://en.cppreference.com/w/cpp/language/operators
    template < typename T >
    typename std::enable_if< std::is_arithmetic<T>::value, vector >::type operator+ ( vector vec, T value )
    { return vec += value ; }

    template < typename T >
    typename std::enable_if< std::is_arithmetic<T>::value, vector >::type operator+ ( T value, const vector& vec )
    { return vec + value ; }

    template < typename T >
    typename std::enable_if< std::is_arithmetic<T>::value, vector >::type operator- ( vector vec, T value )
    { return vec -= value ; }

    template < typename T >
    typename std::enable_if< std::is_arithmetic<T>::value, vector >::type operator* ( vector vec, T value )
    { return vec *= value ; }

    template < typename T >
    typename std::enable_if< std::is_arithmetic<T>::value, vector >::type operator* ( T value, const vector& vec )
    { return vec * value ; }

    template < typename T >
    typename std::enable_if< std::is_arithmetic<T>::value, vector >::type operator/ ( vector vec, T value )
    { return vec /= value ; }
}

int main()
{
    toy::vector a { 1.2, 3,4, 5.6, 7.8, 9.1 } ;
    auto b = a ;
    std::cout << std::boolalpha << (a==b) << '\n' ;
    a = b ;
    std::cout << std::boolalpha << (a==b) << '\n' ;

    b = std::move(a) ;
    for( auto v : 21.3 * b ) std::cout << v << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/f18462c4494e7ba6
http://rextester.com/OQWPQ13202
Last edited on
Topic archived. No new replies allowed.
Pages: 12