基于范围的 for 语句定义冗余
查看 n3092,在第 6.5.4 节中,我们找到了基于范围的 for 循环的等效项。然后它继续说明 __begin
和 __end
等于什么。它区分数组和其他类型,我发现这是多余的(又名令人困惑)。
它表示对于数组类型,__begin
和 __end
就是您所期望的:指向第一个的指针和指向末尾的指针。那么对于其他类型,__begin
和__end
等于begin(__range)
和end(__range)
,其中日常生活活动能力。关联命名空间 std
,以便找到 std::begin
和 std::end
/代码>,§24.6.5。
但是,如果我们查看 std::begin
和 std::end
的定义,它们都是为数组和容器类型定义的。数组版本的作用与上面完全相同:指向第一个的指针,指向末尾的指针。
为什么需要将数组与其他类型区分开来,因为其他类型的定义也同样有效,可以找到 std::begin
和 std::end
?
为方便起见,摘录了一些引文:
§6.5.4 基于范围的
for
语句—如果 _RangeT 是数组类型,则 begin-expr 和 end-expr 分别是 __range 和 __range + __bound,其中 __bound 是数组边界。如果 _RangeT 是未知大小的数组或不完整类型的数组,则程序格式错误。
— 否则,begin-expr 和 end-expr 分别是 begin(__range) 和 end(__range),其中 begin 和 end 是通过参数相关查找来查找的 (3.4.2)。出于此名称查找的目的,命名空间 std 是关联的命名空间。
§24.6.5 范围访问
模板
T* 开始(T (&数组)[N]); 返回:数组。
模板
T* end(T (&数组)[N]); 返回:数组+N。
Looking at n3092, in §6.5.4 we find the equivalency for a range-based for loop. It then goes on to say what __begin
and __end
are equal to. It differentiates between arrays and other types, and I find this redundant (aka confusing).
It says for arrays types that __begin
and __end
are what you expect: a pointer to the first and a pointer to one-past the end. Then for other types, __begin
and __end
are equal to begin(__range)
and end(__range)
, with ADL. Namespace std
is associated, in order to find the std::begin
and std::end
defined in <iterator>
, §24.6.5.
However, if we look at the definition of std::begin
and std::end
, they are both defined for arrays as well as container types. And the array versions do exactly the same as above: pointer to the first, pointer to one-past the end.
Why is there a need to differentiate arrays from other types, when the definition given for other types would work just as well, finding std::begin
and std::end
?
Some abridged quotes for convenience:
§6.5.4 The range-based
for
statement— if _RangeT is an array type, begin-expr and end-expr are __range and __range + __bound, respectively, where __bound is the array bound. If _RangeT is an array of unknown size or an array of incomplete type, the program is ill-formed.
— otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, where begin and end are looked up with argument-dependent lookup (3.4.2). For the purposes of this name lookup, namespace std is an associated namespace.
§24.6.5 range access
template <class T, size_t N> T* begin(T (&array)[N]);
Returns: array.
template <class T, size_t N> T* end(T (&array)[N]);
Returns: array + N.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这避免了 ADL 的极端情况:
因为 ADL 在调用
begin(a)
时找到了 other::begin,所以等效的代码会中断,导致令人困惑的编译错误(类似于“can't Compare”) int to other::T*”,因为end(a)
将返回 T*)或不同的行为(如果定义了 other::end 并做了同样意想不到的事情)。This avoids a corner-case with ADL:
Because ADL finds other::begin when calling
begin(a)
, the equivalent code would break causing a confusing compile error (along the lines of "can't compare int to other::T*" asend(a)
would return a T*) or different behavior (if other::end was defined and did something likewise unexpected).