シンボルテーブルを_std::map
_として実装しています。値については、デフォルトのコンストラクターを介して値型のインスタンスを合法的に構築する方法はありません。ただし、デフォルトのコンストラクターを指定しないと、コンパイラエラーが発生し、コンストラクターをアサートすると、プログラムは正常にコンパイルされますが、それを使用して新しいメンバーを追加しようとすると、_map<K,V>::operator []
_内でクラッシュします。
C++でコンパイル時に_map[k]
_をl値として許可しないようにする方法はありますか(r値として許可します)?
ところで:私はMap.insert(map<K,V>::value_type(k,v))
を使用してマップに挿入できることを知っています。
編集:マップがデフォルトのコンストラクターを呼び出さずに値を作成できるように、値のタイプを変更することになる解決策を提案した人が何人かいます。 これは私が望むものとは正反対の結果になりますそれは後でまでエラーを隠すからです。それが必要な場合は、コンストラクターからアサートを削除するだけで済みます。私Wantは、エラーをさらに早く発生させることです。コンパイル時。ただし、_operator[]
_のr値とl値の使用を区別する方法がないように思われるため、やりたいことができないように思われるので、すべて一緒に使用する必要はありません。 。
コンパイラーにoperator []の2つの使用法を区別させることはできません。これらは同じものだからです。 Operator []は参照を返すため、割り当てバージョンはその参照に割り当てているだけです。
個人的には、迅速で汚いデモコード以外のマップにoperator []を使用することはありません。代わりにinsert()とfind()を使用してください。 make_pair()関数を使用すると、挿入が使いやすくなることに注意してください。
m.insert( make_pair( k, v ) );
C++ 11では、次のこともできます。
m.emplace( k, v );
m.emplace( piecewise_construct, make_Tuple(k), make_Tuple(the_constructor_arg_of_v) );
コピー/移動コンストラクターが提供されていない場合でも。
V
にはデフォルトのコンストラクターがないため、実際には期待できません std::map<K,V>
std::map<K,V>::operator[]
使用可能に。
A std::map<K, boost::optional<V> >
doesにはmapped_type
これはデフォルトで構築可能であり、必要なセマンティクスを備えている可能性があります。詳細については、 Boost.Optional のドキュメントを参照してください(willはそれらに注意する必要があります)。
値型がデフォルトで構成可能でない場合、_operator[]
_は機能しません。
ただし、できることは、便利なようにマップ内の値を取得および設定する無料の関数を提供することです。
例えば:
_template <class K, class V>
V& get(std::map<K, V>& m, const K& k)
{
typename std::map<K, V>::iterator it = m.find(k);
if (it != m.end()) {
return it->second;
}
throw std::range_error("Missing key");
}
template <class K, class V>
const V& get(const std::map<K, V>& m, const K& k)
{
typename std::map<K, V>::const_iterator it = m.find(k);
if (it != m.end()) {
return it->second;
}
throw std::range_error("Missing key");
}
template <class K, class V>
void set(std::map<K, V>& m, const K& k, const V& v)
{
std::pair<typename std::map<K, V>::iterator,bool> result = m.insert(std::make_pair(k, v));
if (!result.second) {
result.first->second = v;
}
}
_
dict.get(key [, default])
in Python(キーが存在しない場合は、提供されたデフォルトを返します)のようなゲッターを検討することもできます(ただし、デフォルトは常にキーがマップにあることがわかっている場合でも、構築されます)。
map<K,V>::at()
を使用します。 map<K,V>::operator []
提供されたキーがまだ存在しない場合、デフォルトで要素を構築しようとします。
std::map<K,V>
から新しいクラスを派生させ、独自のoperator[]
を作成します。 l値として使用できないconst参照を返すようにします。
なぜコンパイルされるのかわからないので、コンパイラーが不足しているコンストラクターを捕まえたはずだと思います。
使用するのはどうですか
map<K,V*>
の代わりに
map<K,V> ?
少し醜いですが、これを回避する1つの方法は、インスタンスが有効かどうかを追跡するメンバー変数を追加することです。デフォルトのコンストラクターはインスタンスを無効としてマークしますが、他のすべてのコンストラクターはインスタンスを有効としてマークします。
代入演算子が新しいメンバー変数を適切に転送することを確認してください。
無効なインスタンスを無視するようにデストラクタを変更します。
他のすべてのメンバー関数を変更して、無効なインスタンスで動作するときにスロー/エラー/アサートします。
その後、マップでオブジェクトを使用できます。適切に構築されたオブジェクトのみを使用する限り、コードは正常に機能します。
繰り返しますが、これは、STLマップを使用したいが、operator []の代わりにinsertandfindを使用したくない場合の回避策です。
C++で演算子のオーバーライドを使用する場合、デフォルトの場合の演算子のセマンティクスにできるだけ厳密に従うことが最善です。デフォルトのセマンティクス。 operator []は、配列内の既存のメンバーを置き換えるものです。 std :: mapがルールを少し曲げているように見えます。それはこの種の混乱につながるので、それは残念です。
Std :: mapの下のoperator []のドキュメント( http://www.sgi.com/tech/stl/Map.html )は次のように述べていることに注意してください。特定のキーに関連付けられています。マップにそのようなオブジェクトがまだ含まれていない場合、operator []はデフォルトのオブジェクトdata_type()を挿入します。」
交換と挿入の扱いを変えることをお勧めします。残念ながら、これはどちらが必要かを知る必要があることを意味します。これは、最初にマップを検索することを意味する場合があります。パフォーマンスが問題になる場合は、メンバーシップをテストして1回のルックアップで挿入できる最適化を見つける必要がある場合があります。
std :: mapを値型に特化することができます。それが良い考えだと言っているわけではありませんが、それは可能です。私は専門にしましたscoped_ptr<FILE>
のdtorをfclose
ではなくdelete
に変更します。
何かのようなもの:
template<class K, class Compare, class Allocator>
my_value_type& std::map<K,my_value_type,Compare,Allocator>::operator[](const K& k)
{
//...
}
これにより、必要なコードをタイプのoperator []に挿入できるようになります。残念ながら、現在のc ++でr値のみを返す方法がわかりません。 c ++ 0xでは、次のものを使用できる場合があります。
template<class K, class Compare, class Allocator>
my_value_type&& std::map<K,my_value_type,Compare,Allocator>::operator[](const K& k)
{
//...
}
これにより、R値の参照(&&)が返されます。