基于范围的语句定义冗余

时间:2010-04-15 20:49:45

标签: c++ for-loop range c++11 argument-dependent-lookup

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

对于数组类型,__begin__end是您所期望的:指向第一个的指针和指向结尾的指针。然后对于其他类型,__begin__end等于begin(__range)end(__range),与ADL相等。命名空间std已关联,以便找到std::begin中定义的std::end<iterator>,§24.6.5。

但是,如果我们查看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)查找。出于此名称查找的目的,namespace std是一个关联的命名空间。

  

§24.6.5范围访问

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

返回:array。

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

返回:array + N。

1 个答案:

答案 0 :(得分:22)

这避免了ADL的角落:

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

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

因为ADL在调用begin(a)时发现了其他:: begin,所以等效的代码会破坏导致混乱的编译错误(沿着“不能将int与其他:: T *比较”为{{1将返回一个T *)或不同的行为(如果定义了其他:: end并做了同样意外的事情)。