samedi 29 août 2015

Simulating the range-based for loop's begin/end behavior

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 _RangeT is an array type, begin-expr and end-expr are __range and __range + __bound, respectively, where __bound is the array bound. If _RangeT is an array of unknown size or an array of incomplete type, the program is ill-formed;
  • if _RangeT is a class type, the unqualified-ids begin and end are looked up in the scope of class _RangeT as 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) and end(__range), respectively, where begin and end are 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.

Aucun commentaire:

Enregistrer un commentaire