Reputation: 27574
Here is the code.
#include <vector>
void moveIterator(std::vector<char>::const_iterator& v) {
v++;
}
int main() {
std::vector<char> v;
std::vector<char>::iterator iter = v.begin();
moveIterator(iter);
}
The compilation failed. Here is the error.
candidate function not viable: no known conversion from 'std::vector<char>::iterator' (aka '__normal_iterator<char *, std::vector<char, std::allocator<char> > >') to 'std::vector<char>::const_iterator &' (aka '__normal_iterator<const char *, std::vector<char, std::allocator<char> > > &') for 1st argument
But it works if I remove &
in the parameter, as follows:
void moveIterator(std::vector<char>::const_iterator v) { // no &
v++;
}
It seems that I cannot apply an iterator
to a function which accepts a reference of const_iterator
, why?
Upvotes: 1
Views: 148
Reputation: 40070
For the same reason you cannot call f(std::string&)
with a std::vector<char>
.
In most implementations,
std::vector<char>::const_iterator
,std::vector<char>::iterator
are two distinct classes and a conversion from one to a (non-const) reference to the other is not possible.
What you could do is define moveIterator
as a template:
template<class InputIt>
void moveIterator(InputIt& it) {
++it;
}
std::vector<int> v;
auto it = v.begin();
auto cit = v.cbegin();
moveIterator(it); // iterator
moveIterator(cit); // const_iterator
Upvotes: 3
Reputation:
A const_iterator
is not a const iterator
they are distinct types.
const std::vector::iterator != std::vector::const_iterator
Upvotes: 0
Reputation: 119877
You can't do this because it would allow all hell to break loose.
Consider this code:
#include <vector>
const std::vector<char> doNotChangeMe; // in ROM
void breakMe(std::vector<char>::const_iterator& v) {
v = doNotChangeMe.cbegin();
}
int main() {
std::vector<char> v;
std::vector<char>::iterator iter = v.begin();
breakMe(iter); // imagine this is allowed
*iter=42; // what happens here?
}
It is basically the same reason why T **
is not convertible to const T **
.
Upvotes: 1
Reputation: 170074
While there is a conversion from iterator
to const_iterator
, this will require a temporary for the reference to bind to, since the argument is not const_iterator
itself. As such, a non-const lvalue reference is a non-starter.
iterator
and const_iterator
don't even need to be class types. Pointers are iterators too (and are in fact the iterators types of a vector in an optimized build). Consider:
void foo(int const*& p) { }
void bar() {
int i = 0;
foo(&i);
}
Which produces the exact same error.
Upvotes: 2