const_iterator 与迭代器的比较是否定义明确?

Is comparison of const_iterator with iterator well-defined?

考虑以下代码:

#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 一起工作。但根据标准,它实际上定义明确吗?可以安全地比较 iteratorconst_iterator 吗?

Table C++11 标准中的第 23.2.1 节中的 96 为任何容器类型 a.cend() 定义了 操作语义 X(包括std::vector)如下:

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

所以答案是肯定的,因为根据这个定义 cend() 在容器中指的是与 end() 相同的 element/position,并且 X::iterator 必须可以转换为 X::const_iterator(在相同的 table(*) 中也指定了一个要求)。

begin()cbegin() 的答案也是肯定的,原因相同,定义相同 table。)


(*) 在对其他答案的评论中指出,可转换性并不一定意味着比较操作 i1==i2 将始终有效,例如如果 operator==() 是迭代器类型的成员函数,隐式转换将只被右侧参数接受,而不是左侧参数。 24.2.5/6 状态(关于前向迭代器 ab):

If a and b are both dereferenceable, then a == b if and only if *a and *b are bound to the same object

即使迭代器 end()cend() 不可取消引用,上面的语句暗示 operator==() 必须以这样的方式定义,即使 a 是一个常量迭代器而 b 不是,反之亦然,因为 24.2.5 通常是关于前向迭代器的,包括常量和非常量版本——这很清楚,例如从 24.2.5/1。这就是为什么我确信 Table96 中提到可兑换性的措辞也意味着可比性。但正如 cpplearner@ 稍后的回答中所述,这仅在 C++14 中明确明确。

见§23.2.1,Table96:

X::iterator

[...]

any iterator category that meets the forward iterator requirements.

convertible to X::const_iterator

所以,是的,它定义明确。

令人惊讶的是,C++98 和 C++11 并没有说你可以比较 iteratorconst_iterator。这导致 LWG issue 179 and LWG issue 2263。现在在 C++14 中,§ 23.2.1[container.requirements.general]p7

明确允许这样做

In the expressions

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

where i and j denote objects of a container's iterator type, either or both may be replaced by an object of the container's const_iterator type referring to the same element with no change in semantics.