9 ответов:
нет, нет. Самое простое решение-написать свой собственный бесплатный шаблон функции для этого. Что-то вроде:
#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сам по себе не обеспечивает способ сделать это. Ваш выбор:
- дайте типу значения конструктор по умолчанию, который инициализирует его значение, которое вы хотите, или
- оберните карту в свой собственный класс, который предоставляет значение по умолчанию и реализует
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;
более общая версия, поддержка C++98/03 и более контейнеров
работает с общими ассоциативными контейнерами, единственным параметром шаблона является сам тип контейнера.
поддерживаемые контейнеры:
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");
вот подобная реализация с помощью класса-оболочки, который больше похоже на метод
get()наdictвведите в Python:https://github.com/hltj/wxMEdit/blob/master/src/xm/xm_utils.hpptemplate<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");
невозможно указать значение по умолчанию-это всегда значение, построенное по умолчанию (конструктор нулевых параметров).
в самом деле
operator[]вероятно, делает больше, чем вы ожидаете, а если значение не существует для данного ключа в карту можно вставить новое значение из конструктора по умолчанию.
В C++17 обеспечивает
try_emplaceЧто делает именно это. Он принимает ключ и список аргументов для конструктора значений и возвращает пару: aniteratorиbool.: http://en.cppreference.com/w/cpp/container/map/try_emplace
значение инициализируется с помощью конструктора по умолчанию, как и другие ответы сказать. Однако полезно добавить, что в случае простых типов (целочисленные типы, такие как типы int, float, pointer или POD (plan old data)) значения инициализируются нулем (или обнуляются инициализацией значений (что фактически одно и то же), в зависимости от того, какая версия C++ используется).
в любом случае, нижняя линия заключается в том, что карты с простыми типами будут автоматически инициализировать новые элементы. Поэтому в некоторых случаях нет необходимости беспокоиться о явном указании начального значения по умолчанию.
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посмотреть делают ли скобки после имени типа разницу с новым? для получения более подробной информации по этому вопросу.
возможно, вы можете дать пользовательский распределитель, который выделяет значение по умолчанию, которое вы хотите.
template < class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key,T> > > class map;
Comments