Reputation: 1073
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.
Upvotes: 2
Views: 127
Reputation: 409176
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 (i.e. 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.
Upvotes: 4
Reputation: 48948
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.
Upvotes: 3