Рассмотрим спецификацию диапазона для цикла begin-expr и end-expr (N4140 [stmt.ranged]/p1). Учитывая диапазон __range
типа _RangeT
,
begin-expr и end-expr определяются следующим образом:
- if
_RangeT
- тип массива, begin-expr и end-expr -__range
и__range + __bound
, соответственно, где__bound
равно связанный массив. Если_RangeT
- массив неизвестного размера или массив неполного типа, программа плохо сформирована;- Если
_RangeT
- это тип класса, то неквалифицированные-идентификаторыbegin
иend
просматриваются в области класса_RangeT
, как если бы доступ к члену класса поиск (3.4.5), и если либо (или оба) найдут хотя бы один объявления, begin-expr и end-expr являются__range.begin()
и__range.end()
, соответственно;- в противном случае begin-expr и end-expr равны
begin(__range)
иend(__range)
соответственно, гдеbegin
иend
просматриваются в связанные пространства имен (3.4.2). [Примечание: Обычный неквалифицированный поиск (3.4.1) не выполняется. -end note]
Можно ли смоделировать это точное поведение в обычном С++-коде? т.е. можно написать шаблон функции magic_begin
и a magic_end
, так что
for(auto&& p : range_init) { /* statements */ }
и
{
auto&& my_range = range_init;
for(auto b = magic_begin(my_range), e = magic_end(my_range); b != e; ++b){
auto&& p = *b;
/* statements */
}
}
всегда имеют то же самое поведение?
Неответы включают в себя квалифицированные вызовы на std::begin
/std::end
(не обрабатывает третью пулю, между прочим) и using std::begin; begin(range);
, потому что, между прочим, это неоднозначно, если ADL для begin
находит перегрузка, которая одинаково хороша как std::begin
.
Для иллюстрации, данный
namespace foo {
struct A { int begin; };
struct B { using end = int; };
class C { int* begin(); int *end(); }; // inaccessible
struct D { int* begin(int); int* end();};
struct E {};
template<class T> int* begin(T&) { return nullptr; }
template<class T> int* end(T&) { return nullptr; }
}
foo::A a; foo::B b; foo::C c; foo::D d; foo::E e;
Я хочу magic_begin(a)
/magic_begin(b)
/magic_begin(c)
/magic_begin(d)
быть компиляционной ошибкой и magic_begin(e)
для возврата (int*)nullptr
.