std::map default value

后端 未结 12 1933
旧巷少年郎
旧巷少年郎 2020-11-28 06:09

Is there a way to specify the default value std::map\'s operator[] returns when an key does not exist?

相关标签:
12条回答
  • 2020-11-28 06:46

    Expanding on the answer https://stackoverflow.com/a/2333816/272642, this template function uses std::map's key_type and mapped_type typedefs to deduce the type of key and def. This doesn't work with containers without these typedefs.

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

    This allows you to use

    std::map<std::string, int*> m;
    int* v = getWithDefault(m, "a", NULL);
    

    without needing to cast the arguments like std::string("a"), (int*) NULL.

    0 讨论(0)
  • 2020-11-28 06:48
    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;
    
    0 讨论(0)
  • 2020-11-28 06:51

    There is no way to specify the default value - it is always value constructed by the default (zero parameter constructor).

    In fact operator[] probably does more than you expect as if a value does not exist for the given key in the map it will insert a new one with the value from the default constructor.

    0 讨论(0)
  • 2020-11-28 06:53

    More General Version, Support C++98/03 and More Containers

    Works with generic associative containers, the only template parameter 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;
    }
    

    Usage:

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

    Here is a similar implementation by using a wrapper class, which is more similar to the method get() of dict type 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);
    }
    

    Usage:

    std::map<int, std::string> t;
    t[1] = "one";
    string s = wrap_map(t).get(2, "unknown");
    
    0 讨论(0)
  • 2020-11-28 06:53

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

    Anyway, the bottomline is, that maps with simple types will zero-initialize the new items automatically. So in some cases, there is no need to worry about explicitly specifying the default initial 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 Do the parentheses after the type name make a difference with new? for more details on the matter.

    0 讨论(0)
  • 2020-11-28 06:55

    While this does not exactly answer the question, I have circumvented the problem with code like this:

    struct IntDefaultedToMinusOne
    {
        int i = -1;
    };
    
    std::map<std::string, IntDefaultedToMinusOne > mymap;
    
    0 讨论(0)
提交回复
热议问题