На основе диапазона для избыточности определения оператора - PullRequest
19 голосов
/ 16 апреля 2010

Глядя на 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::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 Ответ

22 голосов
/ 16 апреля 2010

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

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

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

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

...