program story

std :: map 기본값

inputbox 2020. 10. 17. 10:29
반응형

std :: map 기본값


키가 존재하지 않을 때 기본값 std::mapoperator[]반환 을 지정하는 방법 이 있습니까?


아니, 없습니다. 가장 간단한 해결책은이를위한 무료 템플릿 함수를 작성하는 것입니다. 다음과 같은 것 :

#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");

다음은 Python get()dict유형 메소드와 더 유사한 래퍼 클래스를 사용하는 유사한 구현입니다 . 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");

기본값을 지정하는 방법은 없습니다. 항상 기본값 (제로 매개 변수 생성자)에 의해 구성된 값입니다.

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.


C++17 provides try_emplace which does exactly this. It takes a key and an argument list for the value constructor and returns a pair: an iterator and a bool.: http://en.cppreference.com/w/cpp/container/map/try_emplace


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.


Maybe you can give a custom allocator who allocate with a default value you want.

template < class Key, class T, class Compare = less<Key>,
       class Allocator = allocator<pair<const Key,T> > > class map;

One workaround is to use map::at() instead of []. If a key does not exist, at throws an exception. Even nicer, this also works for vectors, and is thus suited for generic programming where you may swap the map with a vector.

Using a custom value for unregistered key may be dangerous since that custom value (like -1) may be processed further down in the code. With exceptions, it's easier to spot bugs.

참고URL : https://stackoverflow.com/questions/2333728/stdmap-default-value

반응형