std :: map默认值
有没有一种方法来指定默认值std::map
的operator[]
返回时,一个键不存在?
不,没有。 最简单的解决scheme是编写你自己的免费模板function来做到这一点。 就像是:
#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更新
目的:考虑通用关联容器,以及可选的比较器和分配器参数。
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; }
虽然这并不完全回答这个问题,但我已经用这样的代码绕开了这个问题:
struct IntDefaultedToMinusOne { int i = -1; }; std::map<std::string, IntDefaultedToMinusOne > mymap;
C ++标准(23.3.1.2)指定新插入的值是默认构造的,所以map
本身并不提供这样做的方法。 您的select是:
- 给值types一个默认的构造函数,将其初始化为你想要的值,或者
- 在你自己的类中包装地图,提供一个默认值,并实现
operator[]
来插入该默认值。
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;
没有办法指定默认值 – 它始终是由默认值(零参数构造函数)构造的值。
事实上, operator[]
可能会比你期望的要多,就好像map中不存在给定的键值一样,它会使用默认构造函数的值插入一个新值。
更一般的版本,支持C ++ 98/03和更多的容器
与通用关联容器一起使用,唯一的模板参数是容器types本身。
支持的容器: std::map
, std::multimap
, std::unordered_map
, std::unordered_multimap
, wxHashMap
, QMap
, QMultiMap
, QHash
, QMultiHash
等
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; }
用法:
std::map<int, std::string> t; t[1] = "one"; string s = get_with_default(t, 2, "unknown");
下面是一个类似的实现,它使用了一个类似于Python中的dict
types的方法get()
的包装类: 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); }
用法:
std::map<int, std::string> t; t[1] = "one"; string s = wrap_map(t).get(2, "unknown");
也许你可以给一个自定义的分配器分配一个你想要的默认值。
template < class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key,T> > > class map;
该值是使用默认的构造函数进行初始化,因为其他答案说。 但是,如果添加简单types(int,float,pointer或POD(plan old data)types等整数types),则这些值被初始化为零(或者通过值初始化(这是有效的同样的事情),取决于使用哪个版本的C ++)。
无论如何,底线是,简单types的地图将自动初始化新项目。 所以在某些情况下,不需要担心明确指定默认的初始值。
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
请参阅types名称后的圆括号与新的区别吗? 关于这个问题的更多细节。
C ++ 17提供了try_emplace
,它正是这样做的。 它需要一个键和一个参数列表的值构造函数,并返回一个对:一个iterator
和一个bool
: http : //en.cppreference.com/w/cpp/container/map/try_emplace