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

Rus*_*lan 30 c++ iterator const-iterator comparison-operators

请考虑以下代码:

#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";
}
Run Code Online (Sandbox Code Playgroud)

在这里我介绍了一个错字:在比较中我打电话vec.end()而不是vec.cend().这似乎与gcc 5.2一样有效.但根据标准,它实际上是否定义明确?能iteratorconst_iterator安全地进行比较?

cpp*_*ner 35

令人惊讶的是,C++ 98和C++ 11并没有说你可以将a iterator与a 进行比较const_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
Run Code Online (Sandbox Code Playgroud)

where ij表示容器iterator类型的对象,其中一个或两个可以由容器const_iterator 类型的对象替换,引用相同的元素而不改变语义.

  • 非常好的研究! (2认同)

jog*_*pan 9

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

const_cast<X const &>(a).end()
Run Code Online (Sandbox Code Playgroud)

所以答案是肯定的,因为通过这个定义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为一个常量迭代器和b不,反之亦然,因为24.2.5大约是向前迭代器一般来说,包括常量和非常量版本 - 这一点很明显,例如24.2.5/1.这就是为什么我确信表96中提到可兑换性的措辞也意味着可比性.但正如cpplearner @后来的回答所述,这已经在C++ 14中明确地说明了.


Chr*_*ckl 9

见表23第23.2.1节:

X::iterator
Run Code Online (Sandbox Code Playgroud)

[...]

任何满足前向迭代器要求的迭代器类别.

可转换为 X::const_iterator

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

  • 例如,convertible不排除实现为成员函数的比较运算符,这意味着`i <ci`解析为`i.operator <(ci)`,其中不考虑`i`的转换.标准中可能还有其他保证,但如果是这样,它们应该在答案中. (4认同)
  • _Convertible_并不意味着_comparable_. (3认同)