Является ли сравнение const_iterator с итератором хорошо определенным?

Рассмотрим следующий код:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> vec{1,2,3,5};
    for(auto it=vec.cbegin();it!=vec.cend();++it)
    {
        std::cout << *it;
        // A typo: end instead of cend
        if(next(it)!=vec.end()) std::cout << ",";
    }
    std::cout << "\n";
}

Здесь я ввел опечатку: в сравнении я назвал vec.end() вместо vec.cend(), Похоже, что это работает как задумано с gcc 5.2. Но действительно ли это четко определено в соответствии со Стандартом? Можно iterator а также const_iterator быть в безопасности в сравнении?

3 ответа

Решение

Удивительно, но C++98 и C++11 не сказали, что вы можете сравнить iterator с const_iterator, Это приводит к выпуску 179 LWG и выпуску 2263 LWG. Теперь в C++14 это явно разрешено § 23.2.1[container.requirements.general]p7

В выражениях

i == j
i != j
i < j
i <= j
i >= j
i > j
i - j

где i а также j обозначить объекты контейнера iterator Тип, один или оба могут быть заменены объектом контейнера const_iterator тип ссылается на один и тот же элемент без изменения семантики.

Таблица 96 в стандарте C++11 в разделе 23.2.1 определяет операционную семантику a.cend() для любого типа контейнера X (в том числе std::vector) следующее:

const_cast<X const &>(a).end()

Так что ответ да, потому что по этому определению cend() относится к тому же элементу / положению в контейнере, что и end(), а также X::iterator должен быть конвертируемым в X::const_iterator (требование также указано в той же таблице(*)).

(Ответ также да для begin() против cbegin() по тем же причинам, что определены в той же таблице.)


(*) В комментариях к другим ответам было указано, что конвертируемость не обязательно означает, что операция сравнения i1==i2 всегда будет работать, например, если operator==() является функцией-членом типа итератора, неявное преобразование будет приниматься только для правого аргумента, а не для левого. 24.2.5/6 состояний (о форвард-итераторах a а также b):

Если a а также b оба разыменовываются, то a == b если и только если *a а также *b привязаны к одному и тому же объекту

Хотя итераторы end() а также cend() не разыменование, приведенное выше утверждение подразумевает, что operator==() должны быть определены таким образом, чтобы сравнение было возможно, даже если a является константным итератором и b это не так, и наоборот, потому что 24.2.5 касается прямых итераторов в целом, включая как const-, так и non-const-версии - это ясно, например, из 24.2.5/1. Вот почему я убежден, что формулировка из таблицы 96, которая относится к конвертируемости, также подразумевает сопоставимость. Но, как описано в последующем ответе cpplearner@, это стало ясно ясно только в C++14.

См. §23.2.1, Таблица 96:

X::iterator

[...]

любая категория итераторов, отвечающая требованиям прямого итератора.

конвертируемый вX::const_iterator

Так что да, это четко определено.

Другие вопросы по тегам