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_expression
is an expression of array type, thenbegin_expr
is__range
andend_expr
is(__range + __bound)
, where__bound
is 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
C
that has both a member namedbegin
and a member namedend
(regardless of the type or accessibility of such member), thenbegin_expr
is__range.begin()
andend_expr
is__range.end()
;- Otherwise,
begin_expr
isbegin(__range)
andend_expr
isend(__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