Std :: default value for map

Is it possible to specify the default value std::map operator[] if the key does not exist?

+50
c ++ stdmap
Feb 25 '10 at 11:57
source share
9 answers

No no. The easiest solution is to write your own free template function for this. Something like:

 #include <string> #include <map> using namespace std; template <typename K, typename V> V GetWithDef(const std::map <K,V> & m, const K & key, const V & defval ) { typename std::map<K,V>::const_iterator it = m.find( key ); if ( it == m.end() ) { return defval; } else { return it->second; } } int main() { map <string,int> x; ... int i = GetWithDef( x, string("foo"), 42 ); } 



C ++ 11 update

Purpose: accounting for common associative containers, as well as optional comparator and distributor parameters.

 template <template<class,class,class...> class C, typename K, typename V, typename... Args> V GetWithDef(const C<K,V,Args...>& m, K const& key, const V & defval) { typename C<K,V,Args...>::const_iterator it = m.find( key ); if (it == m.end()) return defval; return it->second; } 
+34
Feb 25 '10 at 12:10
source share

Although this does not exactly answer the question, I circumvented the code issue as follows:

 struct IntDefaultedToMinusOne { int i = -1; }; std::map<std::string, IntDefaultedToMinusOne > mymap; 
+10
Apr 11 '15 at 8:32
source share

The C ++ standard (23.3.1.2) states that the entered default value is configured by default, therefore map alone does not provide a way to execute it. Your choice:

  • Enter a default constructor value type that initializes it to the desired value, or
  • Wrap a map in its class that provides a default value and implements operator[] to insert this default value.
+9
Feb 25 '10 at 12:07
source share
 template<typename T, T X> struct Default { Default () : val(T(X)) {} Default (T const & val) : val(val) {} operator T & () { return val; } operator T const & () const { return val; } T val; }; <...> std::map<KeyType, Default<ValueType, DefaultValue> > mapping; 
+4
Aug 08 2018-12-12T00:
source share

It is not possible to specify a default value - it is always a default value (null parameter constructor).

In fact, operator[] probably does more than you expect, as if for a given key on the map there is no value, it will insert a new one with the value from the default constructor.

+3
Feb 25 '10 at 12:02
source share

More general version, support for C ++ 98/03 and more containers

It works with universal associative containers, the only parameter of the template is the container type itself.

Supported containers: std::map , std::multimap , std::unordered_map , std::unordered_multimap , wxHashMap , QMap , QMultiMap , QHash , QMultiHash , etc.

 template<typename MAP> const typename MAP::mapped_type& get_with_default(const MAP& m, const typename MAP::key_type& key, const typename MAP::mapped_type& defval) { typename MAP::const_iterator it = m.find(key); if (it == m.end()) return defval; return it->second; } 

Using:

 std::map<int, std::string> t; t[1] = "one"; string s = get_with_default(t, 2, "unknown"); 



Here is a similar implementation using a wrapper class that looks more like a get() method of type dict in Python: https://github.com/hltj/wxMEdit/blob/master/src/xm/xm_utils.hpp

 template<typename MAP> struct map_wrapper { typedef typename MAP::key_type K; typedef typename MAP::mapped_type V; typedef typename MAP::const_iterator CIT; map_wrapper(const MAP& m) :m_map(m) {} const V& get(const K& key, const V& default_val) const { CIT it = m_map.find(key); if (it == m_map.end()) return default_val; return it->second; } private: const MAP& m_map; }; template<typename MAP> map_wrapper<MAP> wrap_map(const MAP& m) { return map_wrapper<MAP>(m); } 

Using:

 std::map<int, std::string> t; t[1] = "one"; string s = wrap_map(t).get(2, "unknown"); 
+3
Nov 16 '14 at 15:56
source share

The value is initialized using the default constructor, as other answers say. However, it is useful to add that in the case of simple types (integral types such as int, float, pointer, or POD types (plan old data)), the values ​​are initialized to zeros (or zeroed out by initializing the value (which is effectively the same), depending on which version of C ++ is used).

In any case, the bottom line is that cards with simple types will zero-initialize new elements automatically. Therefore, in some cases, there is no need to worry about explicitly specifying the initial default value.

 std::map<int, char*> map; typedef char *P; char *p = map[123], *p1 = P(); // map uses the same construct inside, causes zero-initialization assert(!p && !p1); // both will be 0 

See Does it contain parentheses after the type name matters with the new? for more information on this.

+2
Mar 07 '14 at 11:49
source share

Perhaps you can provide a custom allocator that highlights the desired default value.

 template < class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key,T> > > class map; 
+1
Feb 25 '10 at
source share

C ++ 17 provides a try_emplace that does just that. It takes the key and argument list for the value constructor and returns a pair: a iterator and a bool .: Http://en.cppreference.com/w/cpp/container/map/try_emplace

0
Jul 10 '17 at 17:22
source share



All Articles