Диапазон, основанный на избыточности определения операторов

Глядя на n3092, в п. 6.5.5 мы находим эквивалентность для цикла, основанного на диапазоне. Затем мы продолжим говорить, что __begin и __end равны. Он различает массивы и другие типы, и я нахожу это избыточным (иначе запутанным).

Он говорит о типах массивов, которые __begin и __end - это то, что вы ожидаете: указатель на первый и указатель на один конец. Затем для других типов __begin и __end равны begin(__range) и end(__range), с ADL. Пространство имен std связано с тем, чтобы найти std::begin и std::end, определенные в <iterator>, §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 начинаются (__ диапазон) и заканчиваются (__ диапазон) соответственно, где начало и конец просматриваются с зависимым от аргумента поиска (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.

Ответ 1

Это позволяет избежать углового случая с ADL:

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

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

Поскольку ADL находит другое:: begin при вызове begin(a), эквивалентный код прерывается, вызывая запутанную ошибку компиляции (по строкам "не может сравнивать int с другим:: T *", поскольку end(a) возвращался T *) или другое поведение (если другой:: конец был определен и сделал что-то также неожиданное).