I have a class like this:
class C {
private:
    std::unordered_map<char, int> m = {{'a', 1}, {'b', 2}, {'c', 3}};
public:
    int operator[](const char& key) const {
        return m.find(key)->second;
    }
};
Is it possible to iterate the elements of the map without modifying the class?
I want to have something like:
for (auto x: c) {
    // x -> a map element
}
                No, a ranged-for loop does not use operator[]
The definition of
for ( range_declaration : range_expression ) loop_statement
Is that it is treated as-if it were (without introducing __names)
{
    auto && __range = range_expression ; 
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) {   
        range_declaration = *__begin; 
        loop_statement    
    } 
} 
With the following rules for begin_expr and end_expr:
- If
 range_expressionis an expression of array type, thenbegin_expris__rangeandend_expris(__range + __bound), where__boundis the number of elements in the array (if the array has unknown size or is of an incomplete type, the program is ill-formed)- If range_expression is an expression of a class type
 Cthat has both a member namedbeginand a member namedend(regardless of the type or accessibility of such member), thenbegin_expris__range.begin()andend_expris__range.end();- Otherwise,
 begin_exprisbegin(__range)andend_exprisend(__range), which are found via argument-dependent lookup (non-ADL lookup is not performed).
A simple change to your class which would suffice would to be add begin and end, delegating to m.begin() and m.end()
class C {
private:
    std::unordered_map<char, int> m = {{'a', 1}, {'b', 2}, {'c', 3}};
public:
    int operator[](const char& key) const {
        return m.find(key)->second; 
        // return m.at(key); or return m[key]; are both safer than this
    }
    std::unordered_map<char, int>::iterator begin() {
        return m.begin();
    }
    // overloaded on the constness of "this"
    std::unordered_map<char, int>::const_iterator begin() const {
        return m.begin();
    }
    std::unordered_map<char, int>::iterator end() {
        return m.end();
    }   
    // overloaded on the constness of "this"
    std::unordered_map<char, int>::const_iterator end() const {
        return m.end();
    }   
};
                        No.
In addition to the constraints imposed specifically by ranged-for, which others have covered, your class does not expose any way to know which elements are in the map, not even the first or last element keys. It does not expose any iterators. It simply does not expose sufficient information to perform iteration.
A class can be iterated if it provides iterators i.e. if begin(c) and end(c) return iterators (or c.begin() and c.end()). Your class doesn't provide iterators, and it won't be possible to implement the iterators outside of the class, since the internal map is private.
So, the answer is no, the class does need to be modified.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With