Search code examples
c++c++11range-based-loop

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


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?


Solution

  • 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