When will this code fail? std::vector implementation constructor

I have successfully implemented (not sure if 100% correctly though) the std::vector, and when implementing SFINAE I tried a code out of curiosity and it oddly worked as expected and it baffled me.

The code is the constructor that is written just below all constructor overloads and the destructor:

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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <iostream>
#include <cmath>
#include <vector>
#include <list>

using namespace std;

class Vector
{
    T* values;
    std::size_t v_size;
    std::size_t  v_capacity;
    bool ctor_initialized = false;

    // sfinae
    template <typename Iter>
    using required_input_iterator = std::enable_if<std::is_base_of_v<std::input_iterator_tag,
          typename std::iterator_traits<Iter>::iterator_category >>;

public:
    using iterator = T*;
    using const_iterator = const T*;
    using reference = T&;
    using const_reference = const T&;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    using size_type = std::size_t;

    Vector();
    explicit Vector(size_type sz);
    Vector(size_type sz, const_reference v );
    Vector(const std::initializer_list<T>& i_list );
    Vector(const Vector&);
    Vector(Vector&&) noexcept;
    Vector<T>& operator=(Vector<T>) noexcept;
//    Vector<T>& operator=(Vector<T>&&) noexcept;
    ~Vector();

   // here is the constructor that I use
  /*  template<typename InputInterator, typename = required_input_iterator<InputInterator> >
    Vector(InputInterator first, InputInterator last) */

    // here the code that I tried
    template<typename InputInterator>//, typename = required_input_iterator<InputInterator> >
    Vector(InputInterator* first, InputInterator* last) : v_size(last - first), v_capacity(v_size),
        values(static_cast<T*>(::operator new (sizeof(T) * v_size)))
    {
        std::copy(first, last, begin());
    }

    // element access
    const_reference front() const;
    reference front();
    const_reference back() const;
    reference back();
    reference operator[ ](size_type i);
    const_reference operator[ ](size_type i) const;
    reference at(size_type i);
    const_reference at(size_type i) const;
    constexpr T* data() noexcept;
    constexpr const_iterator data() const noexcept;

    // iterators
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator  cend() const;
    reverse_iterator rbegin() noexcept;
    const_reverse_iterator crbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator crend() const noexcept;

    // Modifiers
    template<typename... ARGS>
    reference emplace_back(ARGS&&... args);
    template<typename... ARGS>
    iterator emplace(const_iterator pos, ARGS&&... args);
    iterator insert(iterator pos, const_reference v );
    template<typename InputInterator> iterator insert(iterator pos, InputInterator first, InputInterator last );
    iterator insert(const_iterator pos, const_reference v );
    iterator insert(const_iterator pos, reference& v );
    void insert(iterator pos, size_type n, const_reference v );
    iterator insert(const_iterator pos, size_type n, const_reference v );
    void push_back(const_reference v);
    void push_back(reference& v);
    void pop_back();
    iterator erase( const_iterator pos );
    iterator erase( iterator first, iterator last);
    void clear() noexcept;
    void resize(size_type n);
    void resize(size_type n, const_reference v);
    void swap(Vector& other ) noexcept;

    // capacity
    size_type size() const noexcept;
    size_type capacity() const noexcept;
    constexpr bool empty() const noexcept;
    void reserve(size_type n);
    void shrink_to_fit();

    // Non-Member Functions
    template<typename H> friend bool operator==(const Vector<H>& lhs, const Vector<H>& rhs);
    template<typename H> friend bool operator!=(const Vector<H>& lhs, const Vector<H>& rhs);

    // see https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
    friend void swap(Vector<T>& first, Vector<T>& second);

private:
    void reallocate();
};

/* I left out the method definitions because it is too long and wouldn't fit due to its length and I
 think they are not relevant to the question but I will leave a link below with the full code just in case.*/


int main()
{
    Vector<int> vs(5, 4);

    Vector<int>::iterator i;

    vs.shrink_to_fit();

    Vector<string> tx;

    tx.push_back("txeynots");


    Vector<double> nx;

    cout << vs[3] << endl << endl << endl << endl;


    nx.push_back(65);
    nx.push_back(1);
    nx.push_back(2);
    nx.push_back(3);
    nx.pop_back();
    nx.push_back(4);
    nx.push_back(9);
    nx.push_back(5);
    nx.push_back(6);
    nx.push_back(3564);
    nx.push_back(3564);
    nx.push_back(3564);


    Vector<int> xx(nx.cbegin(), nx.cbegin() + 8);

    int ph = 5;;

    Vector<int> fvf(&ph, &ph); // Where I was expecting some trouble but nothing 'wrong' happened

   for(auto iter = fvf.cbegin(); iter != fvf.cend(); ++iter)
        cout << *iter << "  "; // it prints nothing
    cout << endl;


    cout << fvf.capacity()<< endl; // prints 0 (zero)
    cout << fvf.size()<< endl; // prints 0 (zero)
}


Link with the full implementation of the vector : https://drive.google.com/open?id=17h6Xs3pO55KBHGB3bdbAEFFlsQVC0yZx

They all work as supposed but this constructor looks wrong for me:
1
2
 template<typename InputInterator>//, typename = required_input_iterator<InputInterator> >
    Vector(InputInterator* first, InputInterator* last)


When might it fail?
Last edited on
That constructor looks like it will qualify any time your parameters are two pointers to the same underlying type. It will "fail" (i.e. not qualify as the constructor you're trying to use) only if you don't have two pointers to the same underlying type.

You might as well write it:

1
2
 template<typename any_kind_of_object_at_all>
    Vector(any_kind_of_object_at_all* first, any_kind_of_object_at_all* last)


Of course, if you pass pointers that are in some way dangerous (or the relationship twixt first and last is problematic), you'll get a crash when they're used, but that's nothing to do with templates; that's just dangerous pointers.
Last edited on
Ok, Thanks
Topic archived. No new replies allowed.