次のコードがあります。
struct Node
{
int a;
int b;
};
Node node;
node.a = 2;
node.b = 3;
map<int, int> aa;
aa[1]=1; // OK.
map<Node, int> bb;
bb[node]=1; // Compile error.
構造体のインスタンスを にマップしようとするとNode
、int
コンパイル エラーが発生しました。なんで?
次のコードがあります。
struct Node
{
int a;
int b;
};
Node node;
node.a = 2;
node.b = 3;
map<int, int> aa;
aa[1]=1; // OK.
map<Node, int> bb;
bb[node]=1; // Compile error.
構造体のインスタンスを にマップしようとするとNode
、int
コンパイル エラーが発生しました。なんで?
マップのキーとして使用できるものを作成するには、を使用して比較できる必要がありますoperator<()
。このような演算子をノードクラスに追加する必要があります。
struct Node
{
int a;
int b;
bool operator<( const Node & n ) const {
return this->a < n.a; // for example
}
};
もちろん、実際の演算子が何をするかは、構造体にとって実際に比較が何を意味するかによって異なります。
ノードオブジェクトを比較する方法をstd::mapに指示する必要があります。デフォルトでは、less演算子を使用してこれを実行しようとします。ただし、Nodeに未満の演算子を指定していません。最も簡単な解決策は、それを供給することです。
無料の関数の例:
bool operator<(Node const& n1, Node const& n2)
{
return n1.a<n2.a || (n1.a==n2.a && n1.b<n2.b);
}
ノードオブジェクトx、yの任意のペアについて、マップはxとyを等しい(同じキー)と見なすことに注意して!(x<y)
ください!(y<x)
。
ノードタイプの比較を有効にするには、より小さい演算子を定義する必要があります。
struct Node
{
int a;
int b;
};
bool operator<(Node const& n1, Node const& n2)
{
// TODO: Specify condition as you need
return ... ;
}
ここでは、ユーザー定義型のLessThanComparableの意味を確認できます。
別の解決策は、 std::binary_functionに基づいてファンクターを定義することです。設計の観点からは、比較がNode
クラスから効果的に切り離されているため、このオプションには利点があります。これにより、さまざまな比較条件(ファンクター)に特化したマップを定義できます。
#include <map>
struct Node
{
int a;
int b;
};
struct NodeLessThan
: public std::binary_function<Node, Node, bool>
{
bool operator() (Node const& n1, Node const& n2) const
{
// TODO: your condition
return n1.a < n2.a;
}
};
int main()
{
Node node;
node.a = 2;
node.b = 3;
typedef std::map<Node, int, NodeLessThan> node_map_t;
node_map_t bb;
bb[node] = 1;
}
NodeLessThan
したがって、たとえば、異なる条件を使用したりNode::a
、両方のコンポーネントを比較Node::a
する別の条件によってのみ比較したりするなど、より多くの比較を定義できますNode::b
。次に、さまざまなタイプのマップを定義しました。
typedef std::map<Node, int, NodeLessThan> node_map_t;
typedef std::map<Node, int, NodeLessThanByA> node_map_a_t;
このようなデカップリングは煩わしさが少なく(ノードクラスにはまったく触れません)、より拡張可能なソリューションを実現するのに役立ちます。
データをキーでソートする必要が本当にない場合は、新しい unordered_map を使用できます。
#include <unordered_map>
...
std::tr1::unordered_map<Node, int> aa; // Doesn't require operator<(Node, Node)
これを機能させるには、最新のコンパイラが必要です。
UPDATENode
Neilが指摘しているように、キー
付きのunordered_mapが必要な場合は、特殊なハッシュ関数が必要です。
struct NodeHash : std::unary_function<Node, size_t>
{
size_t operator()(Node const & node) const
{
return static_cast<size_t>(node.a + 1) * static_cast<size_t>(node.b + 1);
}
};
そして、マップは次のようになります。
std::tr1::unordered_map<Node, int, NodeHash> aa;
また、sellibitze が言うように、ハッシュ衝突の場合にキーを比較するには operator== が必要です。
bool operator==(const Node & lhs, const Node & rhs)
{
return lhs.a == rhs.a && rhs.b == rhs.b;
}
結局のところ、 std::map の方がはるかに使いやすいと思います。
コンパイラ エラーを投稿していただけますか。何が問題なのかを伝えるためのものです。
Node
マップの要素を識別するために必要な比較演算子を実装していないため、エラーが発生すると思います。