const_iterator和iterator的比较是否被明确定义?

36

考虑以下代码:

#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可以安全地进行比较吗?

3个回答

43

令人惊讶的是,C++98和C++11都没有明确说明你可以将iteratorconst_iterator进行比较。这导致了LWG问题179LWG问题2263。现在在C++14中, § 23.2.1 [container.requirements.general] p7 明确允许这样比较。

在表达式中

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

其中ij表示容器的iterator类型的对象,一个或两个对象都可以被替换为容器的const_iterator类型的对象,这些对象引用相同的元素,并且不会改变语义。


这仅意味着来自同一对象并匹配“容器”概念的const和非const迭代器可以安全地进行比较。但是,您不能对其他迭代器做出这样的假设。 - ABu

11

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

const_cast<X const &>(a).end()
所以答案是肯定的,因为按照这个定义,cend()end() 在容器中引用相同的元素/位置,并且 X::iterator 必须可以转换为 X::const_iterator(这也是同一表格(*)中指定的要求)。

(出于相同的原因,在相同的表格中定义了 begin() vs. cbegin() 也是肯定的。)


(*)评论中已经指出,可转换性并不一定意味着比较操作 i1==i2 总是有效,例如如果 operator==() 是迭代器类型的成员函数,则对于右手参数,而不是左手参数,将接受隐式转换。24.2.5/6(关于前向迭代器 ab)规定:

 

如果 ab 都是可解引用的,则当且仅当 *a*b 绑定到相同的对象时,a == b

即使迭代器 end()cend() 不可解引用,上述语句也意味着 operator==() 必须以比较方式定义,即使 a 是 const 迭代器,b 不是,反之亦然,因为 24.2.5 是关于前向迭代器的一般性描述,包括 const 和非 const 版本 -- 这一点从 24.2.5/1 显然。这就是为什么我相信来自表格 96 的措辞,它涉及可转换性,也意味着可比性。但正如 cpplearner@ 后来的答案所描述的那样,这只在 C++14 中明确说明了。


10
X::iterator

[...]

任何符合前向迭代器要求的迭代器类型。

可转换为 X::const_iterator

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


3
“Convertible”并不意味着“可比较”。 - cpplearner
4
例如,可转换性并不排除比较运算符以成员函数实现的情况,意味着i < ci解析为i.operator <(ci),其中不考虑对i进行任何转换。标准中可能会有其他保证,但如果有的话,应该在答案中说明。 - user743382
@hvd:幸运的是,在提问者的代码中,const_iterator在比较的左侧,而普通迭代器在右侧。因此它被转换了。或者我猜我们可以说这很不幸,因为这意味着编译器没有捕捉到对end()的意外使用。 - Steve Jessop
1
@SteveJessop 这只是一个例子。另一个例子是运算符根本不接受 const_iterator,而只接受 const_iterator 隐式可转换的类型,需要两个用户定义的转换。第三个例子是一个模板比较运算符,其中类型参数无法推导出来,因为存在 const_iterator/iterator 不匹配的情况。(幸运的是,现在有一个答案显示了标准中的额外要求。) - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接