What is member interpretation in Range-based for loop (since C++11)?
Asked Answered
M

1

6

I read this documentation for a range-based for loop:

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.

I do not understand this paragraph. What does the member interpretation do so as to forbid the example class being used with the range-based for loop?

Miracle answered 26/1, 2022 at 16:18 Comment(1)
Like the quote says, it'll find the names begin and end inside meow and since those aren't functions that return iterators, the range based for loop can't work.Antitank
C
6

The "member interpretation" refers to begin_expr and end_expr using members of the iterated type in contrast to using plain offsets for arrays or begin and end free functions.

The array interpretation is off the table, because it is only used for arrays. Next consider that there is std::begin and std::end:

Custom overloads of begin may be provided for classes and enumerations that do not expose a suitable begin() member function, yet can be iterated.

Now consider this example:

#include <iostream>
#include <vector>

class meow { 
    enum { begin = 1, end = 2}; 
    public:
    std::vector<int> data;
};

// non-const iterators
auto begin(meow& m){ return m.data.begin(); }
auto end(meow& m) { return m.data.end(); }
// const iterators
auto begin(const meow& m){ return m.data.begin(); }
auto end(const meow& m) { return m.data.end(); }

int main() {
    meow m;
    for (const auto& e : m) {}
}

We want to iterate the meows data. But it does not work. The member interpratation is choosen, even though meow::begin and mewo::end are private and the begin and end functions could be used. Hence the error:

<source>: In function 'int main()':
<source>:17:26: error: 'meow::<unnamed enum> begin' is private within this context
     for (const auto& e : m) {}
                          ^
<source>:5:12: note: declared private here
     enum { begin = 1, end = 2};
            ^~~~~
<source>:17:26: error: 'begin' cannot be used as a function
     for (const auto& e : m) {}
                          ^
<source>:17:26: error: 'meow::<unnamed enum> end' is private within this context
<source>:5:23: note: declared private here
     enum { begin = 1, end = 2};
                       ^~~
<source>:17:26: error: 'end' cannot be used as a function
     for (const auto& e : m) {}
                          ^

The example works fine when we remove the private enum:

#include <iostream>
#include <vector>

class meow { 
    //enum { begin = 1, end = 2}; 
    public:
    std::vector<int> data;
};

// non-const iterators
auto begin(meow& m){ return m.data.begin(); }
auto end(meow& m) { return m.data.end(); }
// const iterators
auto begin(const meow& m){ return m.data.begin(); }
auto end(const meow& m) { return m.data.end(); }

int main() {
    meow m;
    for (const auto& e : m) {}
}

Live Demo

Capparidaceous answered 26/1, 2022 at 16:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.