You can't make the compiler differentiate between the two uses of operator[], because they are the same thing. Operator[] returns a reference, so the assignment version is just assigning to that reference.
Personally, I never use operator[] for maps for anything but quick and dirty demo code. Use insert() and find() instead. Note that the make_pair() function makes insert easier to use:
m.insert( make_pair( k, v ) );
In C++11, you can also do
m.emplace( k, v );
m.emplace( piecewise_construct, make_tuple(k), make_tuple(the_constructor_arg_of_v) );
even if the copy/move constructor is not supplied.
Use map<K,V>::at()
. map<K,V>::operator []
will try to default-construct an element if the key provided does not already exist.
Your V
doesn't have a default constructor, so you cannot really expect std::map<K,V>
std::map<K,V>::operator[]
to be usable.
A std::map<K, boost::optional<V> >
does have a mapped_type
that is default-constructible, and likely has the semantics you want. Refer to the Boost.Optional documentation for details (you will need to be aware of them).
If the value-type is not default-constructible, then operator[]
just won't work for you.
What you can do, though, is to provide free functions that get and set values in a map for convenience.
E.g:
template <class K, class V>
V& get(std::map<K, V>& m, const K& k)
{
typename std::map<K, V>::iterator it = m.find(k);
if (it != m.end()) {
return it->second;
}
throw std::range_error("Missing key");
}
template <class K, class V>
const V& get(const std::map<K, V>& m, const K& k)
{
typename std::map<K, V>::const_iterator it = m.find(k);
if (it != m.end()) {
return it->second;
}
throw std::range_error("Missing key");
}
template <class K, class V>
void set(std::map<K, V>& m, const K& k, const V& v)
{
std::pair<typename std::map<K, V>::iterator,bool> result = m.insert(std::make_pair(k, v));
if (!result.second) {
result.first->second = v;
}
}
You might also consider a getter like dict.get(key [, default])
in Python (which returns the provided default if key is not present (but that has a usability problem in that the default always has to be constructed, even if you know that key is in the map).
Derive a new class from std::map<K,V>
and create your own operator[]
. Have it return a const reference, which can't be used as an l-value.
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