Почему STL требует временную переменную итератора для ее компиляции?
Вот очень простой фрагмент кода:
#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;
}
Объявление строки newVec1
компилируется.
Объявление строки newVec2
завершается с ошибкой:
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
Оба g++ и Visual Studio не могут скомпилировать это, любая идея почему?
myVec.begin()
совпадает с first
...
Ответы
Ответ 1
myVec.begin()
не совпадает с first
. first
имеет тип std::vector<int>::const_iterator
, тогда как myVec.begin()
имеет тип std::vector<int>::iterator
.
Если вы хотите использовать итератор const, используйте cbegin
:
std::vector<int> newVec2(myVec.cbegin(), last);
Ответ 2
vec.begin()
не совпадает с first
, потому что он вернет вам итератор, а не const_iterator
.
Это происходит потому, что наличие константного или не-константного итератора зависит от типа доступа к контейнеру, а не от использования, которое вы хотите использовать с итератором, и это также причина, по которой, например, создание прокси-серверов единственный способ отделить чтение от операций записи в подобных массиве объектах ::operator[]
вместо того, чтобы просто полагаться на версию const или не const.
Это просто из многих случаев, когда концепция const-correctness показывает свои пределы.