Почему std:: distance не работает на смешивание итераторов const и nonconst?

Как и в вопросе, мне интересно, почему. Потому что я получаю сообщение об ошибке, когда пытаюсь получить расстояние между итераторами const и non const.

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> >&)

Из моего ограниченного понимания итераторов я не вижу причин, почему это не должно работать.

Ответ 1

У вас есть изменяемый итератор и константный итератор при вызове std::distance, поэтому вывод аргумента шаблона не выполняется. Вы можете исправить это, указав аргумент шаблона явно.

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

auto dist = std::distance<std::vector<int>::const_iterator>( i1, i2 );

Ответ 2

Это потому, что std:: distance() принимает только один параметр шаблона:

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

Следовательно, first и last должны быть конвертированы в один и тот же тип, а разрешение шаблона, к сожалению, не учитывает, что vector<int>::iterator можно конвертировать в vector<int>::const_iterator.

Ответ 3

Как все говорят, потому что std::distance принимает только один тип итератора, а вывод аргумента шаблона не может выбрать, какой он должен быть (хотя возможно только одно из них, учитывая, что iterator преобразуется в const_iterator но не назад).

Возможно, стоит написать шаблон примерно так:

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

Затем вы можете заставить вывод шаблона следующим образом:

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

вместо того, чтобы записывать этот большой длинный тип. Параметр Container& является позором, потому что AFAIK Container не может быть выведен из одного аргумента итератора.

Ответ 4

std::distance будет работать с этими двумя итераторами, что не работает, это вывод аргумента шаблона. Компилятор пытается решить, какой тип заменить первый аргумент шаблона и имеет два потенциальных кандидата, которые по стандарту заканчиваются сбоем.

Вы можете сделать одну из двух вещей, либо сравнить только итераторы того же типа, либо предоставить тип шаблону:

std::distance<std::vector<int>::const_iterator>( v.begin(), v.cbegin() );