Searene
Searene

Reputation: 27574

Why can't I apply an iterator to a function which accepts a reference of const_iterator?

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

Answers (4)

YSC
YSC

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,
  • and 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

user4290866
user4290866

Reputation:

A const_iterator is not a const iterator they are distinct types.

const std::vector::iterator != std::vector::const_iterator

Upvotes: 0

n. m. could be an AI
n. m. could be an AI

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

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

Related Questions