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 一起工作。但根据标准,它实际上定义明确吗?可以安全地比较 iterator
和 const_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 状态(关于前向迭代器 a
和 b
):
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 并没有说你可以比较 iterator
和 const_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.
考虑以下代码:
#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 一起工作。但根据标准,它实际上定义明确吗?可以安全地比较 iterator
和 const_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 状态(关于前向迭代器 a
和 b
):
If
a
andb
are both dereferenceable, thena == 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 并没有说你可以比较 iterator
和 const_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
andj
denote objects of a container'siterator
type, either or both may be replaced by an object of the container'sconst_iterator
type referring to the same element with no change in semantics.