If a std::map
is const
, then its values are constant too. For example, I can't do this
void EditValue(const std::map<std::string, std::string>& m) {
std::string& value = m.at("mykey"); // <-- compile error
value.append("suffix");
}
But I could do this:
void EditValue(const std::map<std::string, std::string*>& m) {
std::string* value = m.at("mykey");
value->append("suffix"); // <-- this is fine
}
Is there no way to pass a non-pointer map
and have only the values be mutable?
Is there no way to pass a non-pointer
map
and have only the values be mutable?
If the signature is fixed to be
void EditValue(const std::map<std::string, std::string>& m);
then, no, not without a const_cast
inside the function, which is not under your control if I understand your comments correctly. It's also unsafe since you must not modify an object declared const
and the function has no way of knowing if it is.
Otherwise, you could create a wrapper class template for this special scenario. Inside it, you'll keep a mutable
instance of your map and provide accessors just like the normal std::map
but with the exception that functions returning a T&
can be const
qualified - so you only need one at
for example.
Example:
template <class Key, class T>
class map_mutable_values {
public:
template <class K>
T& at(const K& key) const { // const qualified but returns non-const T&
return m_data.at(key);
}
template <class... Args>
auto emplace(Args&&... args) {
return m_data.emplace(std::forward<Args>(args)...);
}
// add the rest of the member functions you want
private:
mutable std::map<Key, T> m_data; // note: mutable
};
This would now work:
void EditValue(const map_mutable_values<std::string, std::string>& m) {
std::string& value = m.at("mykey"); // <-- compiles fine
value.append("suffix");
// m.emplace("Hello", "world"); // error, m is const
}
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