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一样有效.但根据标准,它实际上是否定义明确?能iterator
和const_iterator
安全地进行比较?
cpp*_*ner 35
令人惊讶的是,C++ 98和C++ 11并没有说你可以将a iterator
与a 进行比较const_iterator
.这导致LWG问题179和LWG问题2263.现在在C++ 14中,§23.2.1[container.requirements.general] p7明确允许这一点
在表达式中
Run Code Online (Sandbox Code Playgroud)i == j i != j i < j i <= j i >= j i > j i - j
where
i
和j
表示容器iterator
类型的对象,其中一个或两个可以由容器const_iterator
类型的对象替换,引用相同的元素而不改变语义.
C++ 11标准中的表96在23.2.1节中定义了任何容器类型(包括)的操作语义,如下所示:a.cend()
X
std::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个州(关于前向迭代器a
和b
):
如果
a
和b
都是可解除引用的,那么a == b
当且仅当*a
和*b
并且绑定到同一个对象时
即使迭代器end()
和cend()
不提领,上面的语句,意味着operator==()
必须以这样的方式比较是可能的,即使被定义a
为一个常量迭代器和b
不,反之亦然,因为24.2.5大约是向前迭代器一般来说,包括常量和非常量版本 - 这一点很明显,例如24.2.5/1.这就是为什么我确信表96中提到可兑换性的措辞也意味着可比性.但正如cpplearner @后来的回答所述,这已经在C++ 14中明确地说明了.
见表23第23.2.1节:
Run Code Online (Sandbox Code Playgroud)X::iterator
[...]
任何满足前向迭代器要求的迭代器类别.
可转换为
X::const_iterator
所以,是的,它定义明确.