std:: wartość domyślna mapy

Czy istnieje sposób, aby określić wartość domyślną std::map's operator[] zwraca, gdy klucz nie istnieje?

 64
Author: Sergey K., 2010-02-25

9 answers

Nie, Nie ma. najprostszym rozwiązaniem jest napisanie w tym celu własnej funkcji darmowego szablonu. Coś w stylu:

#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

Przeznaczenie: uwzględnianie ogólnych kontenerów asocjacyjnych, a także opcjonalnych parametrów komparatora i alokatora.

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;
}
 38
Author: WhozCraig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-05 15:49:00

Chociaż to nie do końca odpowiada na pytanie, obejrzałem problem z takim kodem:

struct IntDefaultedToMinusOne
{
    int i = -1;
};

std::map<std::string, IntDefaultedToMinusOne > mymap;
 17
Author: SurvivalMachine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-11 08:32:59

Standard C++ (23.3.1.2) określa, że nowo wstawiona wartość jest domyślnie skonstruowana, więc sama map nie zapewnia sposobu na to. Twoje wybory to:

  • nadaj typowi wartości domyślny konstruktor, który inicjalizuje go na żądaną wartość, lub
  • zawiń mapę w swoją własną klasę, która dostarcza domyślną wartość i implementuje operator[], Aby wstawić tę domyślną.
 11
Author: Mike Seymour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-25 12:07:42
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
Author: Thomas Eding,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-08 17:49:00

Bardziej ogólna wersja, Obsługa C++98/03 i więcej kontenerów

Działa z ogólnymi kontenerami asocjacyjnymi, jedynym parametrem szablonu jest sam typ kontenera.

Obsługiwane kontenery: std::map, std::multimap, std::unordered_map, std::unordered_multimap, wxHashMap, QMap, QMultiMap, QHash, QMultiHash, itd.

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;
}

Użycie:

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

Tutaj jest podobna implementacja przy użyciu klasy wrapper, która jest bardziej podobna do metody get() typu dict w Pythonie: 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);
}

Użycie:

std::map<int, std::string> t;
t[1] = "one";
string s = wrap_map(t).get(2, "unknown");
 4
Author: jyw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-19 17:21:47

Nie można określić wartości domyślnej - jest to zawsze wartość konstruowana przez konstruktor default (parametr zerowy).

W rzeczywistości operator[] prawdopodobnie robi więcej, niż się spodziewasz, ponieważ jeśli wartość nie istnieje dla danego klucza na mapie, wstawia nowy z wartością z domyślnego konstruktora.

 3
Author: Michael Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-25 17:46:59

C++17 dostarcza try_emplace, co robi dokładnie to. Pobiera klucz i listę argumentów dla konstruktora wartości i zwraca parę: an iterator i a bool.: http://en.cppreference.com/w/cpp/container/map/try_emplace

 3
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-10 17:22:32

Wartość jest inicjalizowana przy użyciu domyślnego konstruktora, jak mówią inne odpowiedzi. Warto jednak dodać, że w przypadku typów prostych (typów całkowych, takich jak typy int, float, pointer lub POD (plan old data)), wartości są inicjalizowane zerem (lub zerowane przez inicjalizację wartości (co w praktyce jest tym samym), w zależności od tego, która wersja C++ jest używana).

W każdym razie, dolna linia jest taka, że mapy z prostymi typami automatycznie zerują nowe elementy. Więc w niektórych przypadki, nie ma potrzeby martwić się o jawne podanie domyślnej wartości początkowej.

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

Zobacz czy nawiasy po nazwie typu różnią się od new?Po więcej szczegółów w tej sprawie.

 2
Author: the swine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:30

Może możesz dać Niestandardowy alokator, który przydziela z domyślną wartością, którą chcesz.

template < class Key, class T, class Compare = less<Key>,
       class Allocator = allocator<pair<const Key,T> > > class map;
 1
Author: VDVLeon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-25 12:06:45