是不是可以在结构中使用stl map?

时间:2010-02-06 18:55:24

标签: c++ stl comparison map

struct Node
{
 int a;
 int b;
};

Node node;
node.a = 2;
node.b = 3;

map<int, int> aa;
aa[1]=1; //O.K.

map<Node, int> bb;
bb[node]=1; //Compile Error

当我尝试将结构映射到int时,它给了我一个编译错误。 为什么? 谢谢!

6 个答案:

答案 0 :(得分:23)

要将某个内容用作地图中的键,您必须能够使用operator<()进行比较。您需要将这样的运算符添加到节点类:

struct Node
{
 int a;
 int b;

 bool operator<( const Node & n ) const {
   return this->a < n.a;   // for example
 }
};

当然,真正的算子所做的取决于比较对你的结构实际意味着什么。

答案 1 :(得分:9)

你必须告诉std :: map如何比较Node对象。默认情况下,它尝试使用小于运算符。但是你没有为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)!(y<x),地图会将x和y视为相等(相同的键)。

答案 2 :(得分:6)

您需要定义less-than运算符以启用Node类型的比较:

struct Node
{
 int a;
 int b;
};

bool operator<(Node const& n1, Node const& n2)
{  
   // TODO: Specify condition as you need
   return ... ;
}

您可以在此处查看LessThan Comparable对用户定义类型的含义。

替代解决方案是基于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::aNode::b。然后,定义不同类型的地图:

typedef std::map<Node, int, NodeLessThan>    node_map_t;
typedef std::map<Node, int, NodeLessThanByA> node_map_a_t;

这种解耦不那么具有侵入性(根本不会触及Node类),有利于实现更具可扩展性的解决方案。

答案 3 :(得分:3)

如果您不需要按键对数据进行排序,则可以使用新的unordered_map:

#include <unordered_map>

... 

std::tr1::unordered_map<Node, int> aa;  // Doesn't require operator<(Node, Node)

你需要一个最近的编译器来实现这个目的。

<强>更新 正如Neil所指出的,如果你想要一个带有Node个密钥的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所说,在哈希冲突的情况下需要运算符==来比较密钥:

bool operator==(const Node & lhs, const Node & rhs)
{
    return lhs.a == rhs.a && rhs.b == rhs.b;
}

所以我猜std :: map毕竟更容易使用。

答案 4 :(得分:1)

你能否发布编译错误 - 他们打算告诉什么是错的

我猜你的错误发生了,因为Node没有实现地图所需的比较运算符,以便识别它的元素。

答案 5 :(得分:0)

std::map按其键排序时,您必须定义如何比较两个Node对象。由于C++11,您还可以使用lambda expression而不是定义比较运算符。结果,您可以使代码简短,如下所示:

int main() {
    Node node{ 2, 3 };

    auto comp = [](const Node& n1, const Node& n2) {
        return n1.a < n2.a || (n1.a == n2.a && n1.b < n2.b);
    };
    std::map<Node, int, decltype(comp)> bb(comp);
    bb[node] = 1;

    for (auto const &kv : bb)
        std::cout << kv.first.a << ", " << kv.first.b << ": " << kv.second << std::endl;

    return 0;
}

输出:

  

2,3:3

请根据需要替换lambda表达式的正文。

Code on Ideone