Consider the specification of the range-based for loop's begin-expr and end-expr (N4140 [stmt.ranged]/p1). Given a range __range of type _RangeT,
begin-expr and end-expr are determined as follows:
- if
_RangeTis an array type, begin-expr and end-expr are__rangeand__range + __bound, respectively, where__boundis the array bound. If_RangeTis an array of unknown size or an array of incomplete type, the program is ill-formed;- if
_RangeTis a class type, the unqualified-idsbeginandendare looked up in the scope of class_RangeTas if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration, begin-expr and end-expr are__range.begin()and__range.end(), respectively;- otherwise, begin-expr and end-expr are
begin(__range)andend(__range), respectively, wherebeginandendare looked up in the associated namespaces (3.4.2). [ Note: Ordinary unqualified lookup (3.4.1) is not performed. —end note ]
Is it possible to simulate this exact behavior in ordinary C++ code? i.e., can we write a magic_begin and a magic_end function template such that
for(auto&& p : range_init) { /* statements */ }
and
{
auto&& my_range = range_init;
for(auto b = magic_begin(my_range), e = magic_end(my_range); b != e; ++b){
auto&& p = *b;
/* statements */
}
}
always have the exact same behavior?
Non-answers include qualified calls to std::begin/std::end (doesn't handle the third bullet, among other things) and using std::begin; begin(range); because, among other things, that is ambiguous if ADL for begin finds an overload that's equally good as std::begin.
For illustration, given
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;
I want magic_begin(a)/magic_begin(b)/magic_begin(c)/magic_begin(d) to be a compile error, and magic_begin(e) to return (int*)nullptr.
magic_endto be a compile error forb, right? - Columbomagic_beginandmagic_endresult in an error". - T.C.final? - Columbo