2015-02-13 13 views
14

Tutaj jest bardzo prosty kawałek kodu:Dlaczego STL wymaga tymczasowej zmiennej iteratora, aby to skompilować?

#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; 
} 

Linia deklarując newVec1 kompiluje.

Linia deklarując newVec2 niepowodzeniem z następującym błędem:

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 

Zarówno g ++ i Visual Studio nie skompilować ten, jakiś pomysł dlaczego? myVec.begin() jest taka sama jak first ...

+5

komunikat o błędzie jest oczywisty, oba iteratory muszą być tego samego typu. w twoim przypadku jeden to const_iterator, drugi nie jest –

+0

Nie, nie jest. 'first' jest const. –

+0

Nie nazwałbym tego komunikatu o błędzie jednoznacznie, ale wszystkie bity rzeczywiście istnieją. Najważniejsze jest określenie przewidywanych typów konfliktów dla parametru _InputIterator (__gnu_cxx :: __ normal_iterator > 'i' __gnu_cxx :: __ normal_iterator > ') '" (porównaj 'int *' kontra 'const int *') – hvd

Odpowiedz

34

myVec.begin() nie jest taka sama jak first. first jest typu std::vector<int>::const_iterator, natomiast myVec.begin() jest typu std::vector<int>::iterator.

Jeśli chcesz const iterator, użyj cbegin:

std::vector<int> newVec2(myVec.cbegin(), last); 
+0

Dobra uwaga, dzięki. Tęsknię za tym szczegółem, ponieważ 'std :: vector :: const_iterator first = myVec.begin()' automatycznie rzuca nie const do const ... – jpo38

+0

Jeszcze jedna uwaga: jeśli konstruktor std :: vector używał iteratorów według wartości, konwersja mogłaby dzieje się automatycznie. Twój kod był jednak równoważny konwersji std :: vector :: const_iterator & firstRef = myVec.begin(); , które zawiedzie z tym samym komunikatem o błędzie. – IMil

+1

@IMil: Konstruktor _does_ pobiera iteratory według wartości. Problem polega jednak na tym, że odliczanie argumentów w szablonie nie powiedzie się, ponieważ kompilator nie może zdecydować, do którego typu iteratorów należy utworzyć instancję. –

2

vec.begin() nie jest taka sama jak first ponieważ będzie to powrót iterator, a nie const_iterator.

Dzieje się tak, ponieważ posiadanie stałego lub stałego iteratora zależy od rodzaju dostępu do kontenera, a nie od tego, co chcesz zrobić z iteratorem, i to jest powód, dla którego na przykład tworzenie serwerów proxy jest jedynym sposobem na oddzielenie operacji odczytu od zapisu w obiektach tablicowych, takich jak ::operator[], zamiast polegać tylko na wersji const lub non const.

To tylko wiele z tych przypadków, w których koncepcja poprawności const pokazuje swoje ograniczenia.

Powiązane problemy