キーが存在しないときにstd::map
のoperator[]
が返すデフォルト値を指定する方法はありますか?
いいえ、ありません。最も簡単な解決策は、これを行うための独自の無料のテンプレート関数を作成することです。何かのようなもの:
#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[]
を実装する独自のクラスでマップをラップして、そのデフォルトを挿入します。より一般的なバージョン、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のdict
型のget()
メソッドに似ているラッパークラスを使用した同様の実装を次に示します。 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");
_
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++ 17はtry_emplace
これはまさにこれを行います。値コンストラクタのキーと引数リストを受け取り、iterator
とbool
のペアを返します。 http://en.cppreference.com/w/ cpp/container/map/try_emplace
デフォルト値を指定する方法はありません。常にデフォルト(ゼロパラメーターコンストラクター)によって構築された値です。
実際には operator[]
は、マップ内の指定されたキーに値が存在しない場合、デフォルトのコンストラクターからの値を持つ新しいキーを挿入するため、おそらく予想以上のことを行います。
他の答えが示すように、値はデフォルトのコンストラクタを使用して初期化されます。ただし、単純型(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と違いがありますか? 」を参照してください。
たぶん、あなたはあなたが望むデフォルト値で割り当てるカスタムアロケータを与えることができます。
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
回避策の1つは、_[]
_の代わりにmap::at()
を使用することです。キーが存在しない場合、at
は例外をスローします。さらに良いことに、これはベクターに対しても機能するため、マップをベクターと交換できる汎用プログラミングに適しています。
未登録のキーにカスタム値を使用すると、そのカスタム値(-1など)がコード内でさらに処理される可能性があるため、危険な場合があります。例外を除き、バグを簡単に見つけることができます。