基于范围的语句定义冗余

GMa*_*ckG 19 c++ for-loop range argument-dependent-lookup c++11

查看n3092,在§6.5.4中,我们找到了基于范围的for循环的等价性.然后它继续说什么__begin__end等于.它区分了数组和其他类型,我觉得这是多余的(也就是令人困惑).

它表示数组类型__begin__end你所期望的:指向第一个的指针和指向一个结尾的指针.那么对于其他类型的,__begin__end等于begin(__range)end(__range),与ADL.命名空间std是关联的,以便在第24.6.5节中找到std::beginstd::end定义<iterator>.

但是,如果我们看的定义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]);
Run Code Online (Sandbox Code Playgroud)

返回:数组.

template <class T, size_t N> T* end(T (&array)[N]);
Run Code Online (Sandbox Code Playgroud)

返回:数组+ N.

小智 22

这避免了ADL的角落情况:

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

other::T a[3];
for (auto v : a) {}
Run Code Online (Sandbox Code Playgroud)

因为ADL在调用时发现了其他:: begin begin(a),所以等效的代码会破坏,导致一个令人困惑的编译错误(沿着"不能将int与其他:: T*比较",如同end(a)返回T*)或不同的行为(如果other :: end被定义并做了同样出乎意料的事情).

  • 很好:)它还允许用户使用循环而不包括任何标头. (8认同)
  • 一行摘要:通过ADL查找`begin`和`end`可能找不到`std :: begin`和`std :: end`. (4认同)