Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why std::distance doesnt work on mix of const and nonconst iterators? [duplicate]

Like the question says, I'm wondering about the reason for that. Because I get an error when I try to get the distance between const and non-const iterators.

vector<int> v;
auto it=v.begin();
auto cit=v.cbegin();
distance(it,cit);


no matching function for call to ‘distance(__gnu_cxx::__normal_iterator<int*, std::vector<int> >&, __gnu_cxx::__normal_iterator<const int*, std::vector<int> >&)

From my limited understanding of iterators, I see no reason why it shouldn't work.

like image 562
NoSenseEtAl Avatar asked Mar 08 '12 17:03

NoSenseEtAl


3 Answers

You have a mutable iterator and a constant iterator in the call to std::distance, so template argument deduction is failing. You can fix this by specifying the template argument explicitly.

std::vector<int> v;
auto i1 = v.begin();
auto i2 = v.cbegin();

auto dist = std::distance<std::vector<int>::const_iterator>( i1, i2 );
like image 114
Praetorian Avatar answered Nov 02 '22 20:11

Praetorian


That's because std::distance() only takes one template parameter:

template <class InputIterator>
iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last);

Therefore, first and last must be convertible to the same type, and template resolution will unfortunately not consider that vector<int>::iterator is convertible to vector<int>::const_iterator.

like image 40
Frédéric Hamidi Avatar answered Nov 02 '22 18:11

Frédéric Hamidi


As everyone says, it's because std::distance only takes one iterator type, and template argument deduction is not able to choose which one it should be (even though only one of them is possible given that iterator converts to const_iterator but not back).

It might be worth writing a template something like this:

template <typename Container>
typename Container::const_iterator constify(const Container &, typename Container::iterator it) {
    return it;
}

Then you can force the template deduction like this:

std::distance(constify(v, it), cit);

instead of writing out that great long type. The Container& parameter is a shame, it's there because AFAIK Container can't be deduced from an iterator argument alone.

like image 4
Steve Jessop Avatar answered Nov 02 '22 19:11

Steve Jessop