107

キーが存在しない場合のデフォルト値std::mapの戻り値を指定する方法はありますか?operator[]

4

15 に答える 15

64

いいえ、ありません。最も簡単な解決策は、これを行う独自の無料のテンプレート関数を作成することです。何かのようなもの:

#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;
}
于 2010-02-25T12:10:37.973 に答える
59

これは質問に正確に答えるものではありませんが、次のようなコードで問題を回避しました。

struct IntDefaultedToMinusOne
{
    int i = -1;
};

std::map<std::string, IntDefaultedToMinusOne > mymap;
于 2015-04-11T08:32:59.663 に答える
13

C++17 はtry_emplace、まさにこれを行うものを提供します。値コンストラクターのキーと引数リストを取り、ペアを返します: aniteratorと a bool.: http://en.cppreference.com/w/cpp/container/map/try_emplace

于 2017-07-10T17:22:32.253 に答える
11

C++ 標準 (23.3.1.2) は、新しく挿入された値がデフォルトで構築されることを指定しているため、それmap自体はそれを行う方法を提供していません。選択肢は次のとおりです。

  • 値の型に、必要な値に初期化する既定のコンストラクターを指定するか、または
  • operator[]デフォルト値を提供し、そのデフォルトを挿入するために実装する独自のクラスでマップをラップします。
于 2010-02-25T12:07:42.957 に答える
6

より一般的なバージョン、C++98/03 およびその他のコンテナーをサポート

汎用の連想コンテナーで動作します。唯一のテンプレート パラメーターはコンテナー タイプ自体です。

サポートされているコンテナ: std::mapstd::multimapstd::unordered_mapstd::unordered_multimapwxHashMapQMapQMultiMapQHashなど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()により似ています: https://github.com/hltj/wxMEdit/blob/master/src/xm/xm_utils.hppdict

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");
于 2014-11-16T15:56:45.190 に答える
5
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;
于 2012-08-08T17:49:00.673 に答える
5

他の回答が言うように、値はデフォルトのコンストラクターを使用して初期化されます。ただし、単純な型 (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

型名の後の括弧は new と違いがありますか? を参照してください。詳細については、こちらをご覧ください。

于 2014-03-07T11:49:15.320 に答える
5

デフォルト値を指定する方法はありません。これは常に、デフォルト (ゼロ パラメーター コンストラクター) によって構築された値です。

実際operator[]には、マップ内の指定されたキーの値が存在しないかのように、おそらく期待以上のことを行い、デフォルトのコンストラクターからの値で新しいキーを挿入します。

于 2010-02-25T12:02:36.230 に答える
1

たぶん、あなたが望むデフォルト値で割り当てるカスタムアロケータを与えることができます。

template < class Key, class T, class Compare = less<Key>,
       class Allocator = allocator<pair<const Key,T> > > class map;
于 2010-02-25T12:06:45.127 に答える
0

C++20では、そのような getter を簡単に記述できます。

constexpr auto &getOrDefault(const auto &map, const auto &key, const auto &defaultValue)
{
    const auto itr = map.find(key);
    return itr == map.cend() ? defaultValue : itr->second;
}
于 2021-12-22T00:25:42.087 に答える