Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why STL requires a temporary iterator variable to compile this?

Tags:

c++

iterator

stl

Here is a very straightforward piece of code:

#include <vector>

int main() {

    std::vector<int> myVec(5);
    std::vector<int>::const_iterator first = myVec.begin();
    std::vector<int>::const_iterator last = myVec.begin() + 3;
    std::vector<int> newVec1(first, last);
    std::vector<int> newVec2(myVec.begin(), last);

    return 0;
}

Line declaring newVec1 compiles.

Line declaring newVec2 fails with following error:

prog.cpp: In function 'int main()':
prog.cpp:11:49: error: no matching function for call to 'std::vector<int>::vector(std::vector<int>::iterator, std::vector<int>::const_iterator&)'
     std::vector<int> newVec2(myVec.begin(), last);
                                                 ^
prog.cpp:11:49: note: candidates are:
In file included from /usr/include/c++/4.9/vector:64:0,
                 from prog.cpp:3:
/usr/include/c++/4.9/bits/stl_vector.h:401:9: note: template<class _InputIterator, class> std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const allocator_type&)
         vector(_InputIterator __first, _InputIterator __last,
         ^
/usr/include/c++/4.9/bits/stl_vector.h:401:9: note:   template argument deduction/substitution failed:
prog.cpp:11:49: note:   deduced conflicting types for parameter '_InputIterator' ('__gnu_cxx::__normal_iterator<int*, std::vector<int> >' and '__gnu_cxx::__normal_iterator<const int*, std::vector<int> >')
     std::vector<int> newVec2(myVec.begin(), last);
                                                 ^
In file included from /usr/include/c++/4.9/vector:64:0,
                 from prog.cpp:3:
/usr/include/c++/4.9/bits/stl_vector.h:373:7: note: std::vector<_Tp, _Alloc>::vector(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(initializer_list<value_type> __l,
       ^
/usr/include/c++/4.9/bits/stl_vector.h:373:7: note:   no known conversion for argument 1 from 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}' to 'std::initializer_list<int>'
/usr/include/c++/4.9/bits/stl_vector.h:348:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>&&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(vector&& __rv, const allocator_type& __m)
       ^
/usr/include/c++/4.9/bits/stl_vector.h:348:7: note:   no known conversion for argument 1 from 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}' to 'std::vector<int>&&'
/usr/include/c++/4.9/bits/stl_vector.h:339:7: note: std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(const vector& __x, const allocator_type& __a)
       ^
/usr/include/c++/4.9/bits/stl_vector.h:339:7: note:   no known conversion for argument 1 from 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}' to 'const std::vector<int>&'
/usr/include/c++/4.9/bits/stl_vector.h:335:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>&&) [with _Tp = int; _Alloc = std::allocator<int>]
       vector(vector&& __x) noexcept
       ^
/usr/include/c++/4.9/bits/stl_vector.h:335:7: note:   candidate expects 1 argument, 2 provided
/usr/include/c++/4.9/bits/stl_vector.h:318:7: note: std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = int; _Alloc = std::allocator<int>]
       vector(const vector& __x)
       ^
/usr/include/c++/4.9/bits/stl_vector.h:318:7: note:   candidate expects 1 argument, 2 provided
/usr/include/c++/4.9/bits/stl_vector.h:289:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = unsigned int; std::vector<_Tp, _Alloc>::value_type = int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(size_type __n, const value_type& __value,
       ^
/usr/include/c++/4.9/bits/stl_vector.h:289:7: note:   no known conversion for argument 1 from 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}' to 'std::vector<int>::size_type {aka unsigned int}'
/usr/include/c++/4.9/bits/stl_vector.h:277:7: note: std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = unsigned int; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(size_type __n, const allocator_type& __a = allocator_type())
       ^
/usr/include/c++/4.9/bits/stl_vector.h:277:7: note:   no known conversion for argument 1 from 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}' to 'std::vector<int>::size_type {aka unsigned int}'
/usr/include/c++/4.9/bits/stl_vector.h:264:7: note: std::vector<_Tp, _Alloc>::vector(const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       vector(const allocator_type& __a) _GLIBCXX_NOEXCEPT
       ^
/usr/include/c++/4.9/bits/stl_vector.h:264:7: note:   candidate expects 1 argument, 2 provided
/usr/include/c++/4.9/bits/stl_vector.h:253:7: note: std::vector<_Tp, _Alloc>::vector() [with _Tp = int; _Alloc = std::allocator<int>]
       vector()
       ^
/usr/include/c++/4.9/bits/stl_vector.h:253:7: note:   candidate expects 0 arguments, 2 provided

Both g++ and Visual Studio fail to compile this, any idea why? myVec.begin() is the same as first...

like image 501
jpo38 Avatar asked Feb 13 '15 10:02

jpo38


2 Answers

myVec.begin() is not the same as first. first is of type std::vector<int>::const_iterator, whereas myVec.begin() is of type std::vector<int>::iterator.

If you want a const iterator, use cbegin:

std::vector<int> newVec2(myVec.cbegin(), last);
like image 121
TartanLlama Avatar answered Nov 16 '22 08:11

TartanLlama


vec.begin() is not the same as first because it will return you an iterator, not a const_iterator.

This happens because having a const or non-const iterator depends on the type of the access you have to the container, not on the use you wish to do with the iterator and it's also the reason for which for example creating proxies is the only way to separate read from write operations in array-like objects ::operator[] instead of just rely on const or non-const version.

It's just of the many cases in which the const-correctness concept shows its limits.

like image 23
6502 Avatar answered Nov 16 '22 08:11

6502