简体   繁体   中英

Range based for loop and range type

With reference to the following text snippets mentioned under Range-based for loop

If range_expression is an expression of a class type C that has both a member named begin and a member named end (regardless of the type or accessibility of such member), then begin_expr is __range.begin() and end_expr is __range.end();

The member interpretation is used if the range type has a member named begin and a member named end. This is done regardless of whether the member is a type, data member, function, or enumerator, and regardless of its accessibility. Thus a class like class meow { enum { begin = 1, end = 2}; /* rest of class */ }; cannot be used with the range-based for loop even if the namespace-scope begin/end functions are present.

Is the understanding correct that begin and end should only be the names of member functions of range type (returning possibly iterator type)? Curious to understand the technical reason behind the absence of any workaround for this constraint.

You either need to provide non-member begin and end functions (or otherwise callable objects) that can be found through argument-dependent lookup , or have member functions (or callable objects) explicitly named begin and end which takes no arguments, and which return iterator-like objects (ie they should support postfix ++ and dereference * , and of course could be compared using == ).

As for "technical reasons", it's because range-based for loops are only syntactic sugar for a normal iterator for loop. And the compiler must know which functions to call for the "begin" and "end" iterators.

Is the understanding correct that begin and end should only be the names of member functions of range type (returning possibly iterator type)?

No; actually, most of those are completely valid to be used as begin/end iterator pairs even though they are not member functions!

Here's one using data members:

struct A {
  A() : begin([this] { return array; }), end([this] { return array + 3; }) {}

  int array[3];
  std::function<int*()> begin;
  std::function<int*()> end;
};

Enumerators don't make sense though and types can't be accessed through . . Types that are named or with enumerators named begin and end and that should be iterable are probably very rare, which is probably why no special rule that excludes enumerators was introduced.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM