C++ 常量迭代器与迭代器的比较是否定义良好?
考虑以下代码:C++ 常量迭代器与迭代器的比较是否定义良好?,c++,iterator,comparison-operators,const-iterator,C++,Iterator,Comparison Operators,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
#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";
}
#包括
#包括
int main()
{
std::向量向量向量{1,2,3,5};
对于(自动it=vec.cbegin();it!=vec.cend();++it)
{
C++11标准第23.2.1节中的std::cout表96为任何容器类型X
(包括std::vector
)定义了a.cend()
的操作语义,如下所示:
const_cast<X const &>(a).end()
const_cast(a).end()
因此答案是肯定的,因为根据这个定义,cend()
引用了容器中与end()
相同的元素/位置,X::iterator
必须可转换为X::const_iterator
(同一个表(&ast;)中也指定了一个要求)
(对于begin()
(&ast;)在对其他答案的评论中指出,可兑换性并不一定意味着比较操作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中的措辞,它指的是可兑换性,也意味着可比性。但正如CPPNearner@后面的回答中所述,这一点仅在C++14中明确说明。参见§23.2.1,表96:
[……]
满足正向迭代器要求的任何迭代器类别
可转换为X::const\u迭代器
所以,是的,它定义得很好。令人惊讶的是,C++98和C++11没有说可以将迭代器与常量迭代器进行比较。这导致了和。现在在C++14中,§23.2.1[容器.要求.概述]第7页明确允许这样做
在表达中
i == j
i != j
i < j
i <= j
i >= j
i > j
i - j
i==j
i!=j
ij
i-j
其中i
和j
表示容器的迭代器类型的对象,或者
两者都可以由容器的常量迭代器的对象替换
类型引用相同的元素,语义没有变化
可转换并不意味着可比较。例如,可转换并不排除作为成员函数实现的比较运算符,这意味着i
解析为i.operator@hvd:幸运的是,在提问者的代码中,const_迭代器位于比较的左侧,而普通迭代器位于右侧。因此它被转换。或者我想我们可以说这是不幸的,因为这意味着编译器没有捕捉到end()的意外使用
@SteveJessop这只是一个例子。另一个是完全不接受常量迭代器的运算符,而只是常量迭代器
可以隐式转换为的运算符,需要两个用户定义的转换。第三个是模板比较运算符,其中类型参数由于转换而无法推导st_迭代器
/迭代器
不匹配。(幸运的是,现在有一个答案显示了标准中的附加要求。)这只意味着来自与容器
概念匹配的同一对象的常量迭代器和非常量迭代器可以安全地进行比较。但是,对于其他迭代器,您无法做出这种假设。
i == j
i != j
i < j
i <= j
i >= j
i > j
i - j