20

查看 n3092,在第 6.5.4 节中,我们找到了基于范围的 for 循环的等价物。然后它继续说什么__begin__end等于。它区分了数组和其他类型,我发现这是多余的(又名令人困惑)。

它说的是数组类型,__begin并且__end是您所期望的:指向第一个的指针和指向末尾的指针。然后对于其他类型,__beginand__end等于begin(__range)and end(__range),与 ADL。命名空间std是关联的,以便找到第24.6.5 节中定义的std::begin和。std::end<iterator>

但是,如果我们查看 and 的定义std::beginstd::end它们既是为数组定义的,也是为容器类型定义的。并且数组版本的作用与上面完全相同:指向第一个的指针,指向末尾的指针。

为什么需要将数组与其他类型区分开来,而为其他类型给出的定义也可以正常工作,找到std::beginstd::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 范围访问

template <class T, size_t N> T* begin(T (&array)[N]);

返回:数组。

template <class T, size_t N> T* end(T (&array)[N]);

返回:数组 + N。

4

1 回答 1

22

这避免了 ADL 的极端情况:

namespace other {
  struct T {};
  int begin(T*) { return 42; }
}

other::T a[3];
for (auto v : a) {}

因为 ADL 在调用时会找到 other::begin begin(a),所以等效代码会中断,从而导致令人困惑的编译错误(沿着“无法将 int 与 other::T* 进行比较”这样的行end(a)会返回 T*)或不同的行为(如果other::end 被定义并做了同样意想不到的事情)。

于 2010-04-15T20:54:39.913 回答