C++ 是否不可能将 STL 映射与结构一起用作键?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2214295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:34:35  来源:igfitidea点击:

Is it impossible to use an STL map together with a struct as key?

c++dictionarystlcontainersstdmap

提问by CodingLab

I have the following code:

我有以下代码:

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.

When I tried to map an instance of my struct Nodeto an int, I got a compile error. Why?

当我尝试将结构的一个实例映射Node到 时int,出现编译错误。为什么?

回答by

For a thing to be usable as a key in a map, you have to be able to compare it using operator<(). You need to add such an operator to your node class:

对于可用作地图中的键的事物,您必须能够使用operator<(). 您需要将这样的运算符添加到您的节点类中:

struct Node
{
 int a;
 int b;

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

Of course, what the real operator does depends on what comparison actually means for your struct.

当然,真正的运算符做什么取决于比较对您的结构实际上意味着什么。

回答by sellibitze

You have to tell std::map how to compare the Node objects. By default it tries to do so by using the less than operator. But you didn't provide any less than operator for Node. The easiest solution would be to supply one.

您必须告诉 std::map 如何比较 Node 对象。默认情况下,它会尝试使用小于运算符来执行此操作。但是你没有为 Node.js 提供任何小于操作符。最简单的解决方案是提供一个。

Free function example:

免费功能示例:

bool operator<(Node const& n1, Node const& n2)
{
    return n1.a<n2.a || (n1.a==n2.a && n1.b<n2.b);
}

Note that, for any pair of node objects x,y with !(x<y)and !(y<x)the map will regard x and y as equal (same key).

请注意,对于任何一对节点对象 x,y!(x<y)!(y<x)映射都会将 x 和 y 视为相等(相同的键)。

回答by mloskot

You need to define less-than operator to enable comparisons for your Node type:

您需要定义小于运算符来为您的 Node 类型启用比较:

struct Node
{
 int a;
 int b;
};

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

Here you may check what LessThan Comparablemean for a user-defined type.

在这里,您可以检查LessThan Comparable对用户定义类型的含义。

Alternative solution is to define a functor based on std::binary_function. From design point of view, this option has advantages because comparison is effectively decoupled from the Nodeclass. This makes it possible to define maps specialised with different comparison conditions (functors).

另一种解决方案是定义一个基于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;
}

So, you can define more comparisons than just NodeLessThan, for example using different conditions or one comparing only by Node::aanother comparing both components, Node::aand Node::b. Then, defined different types of maps:

因此,您可以定义更多的比较,而不仅仅是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;

Such decoupling is less intrusive (does not touch Node class at all) and is beneficial to achieve more extensible solution.

这种解耦的侵入性较小(根本不接触 Node 类),有利于实现更具扩展性的解决方案。

回答by Manuel

If you don't really need to have your data sorted by key, you can use the new unordered_map:

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

#include <unordered_map>

... 

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

You'll need a recent compiler for this to work.

你需要一个最新的编译器才能工作。

UPDATEAs Neil points out you need an specialized hash function if you want an unordered_map with Nodekeys.

更新正如尼尔指出的那样,如果您想要一个带有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);
    }
};

And then the map becomes:

然后地图变成:

 std::tr1::unordered_map<Node, int, NodeHash> aa;

Also, as sellibitze says, an operator== is needed to compare keys in case of hash collision:

此外,正如sellibitze所说,在散列冲突的情况下,需要一个运算符==来比较键:

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

So I guess that std::map is much easier to use after all.

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

回答by Dario

Could you please post the compiler error - They're intended to tell you, what's wrong.

您能否发布编译器错误 - 他们旨在告诉,出了什么问题

I guess your error occurs since Nodedoesn't implement a comparison operator which is required by the map in order to identify it's elements.

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

回答by honk

As a std::mapis sorted by its keys, you have to define how to compare two Nodeobjects. Since C++11you can also use a lambda expressioninstead of defining a comparison operator. As a result, you can keep your code as short as follows:

由于std::map按其键排序,您必须定义如何比较两个Node对象。从C++11 开始,您还可以使用lambda 表达式而不是定义比较运算符。因此,您可以保持代码简短,如下所示:

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;
}

Output:

输出:

2, 3: 1

2, 3: 1

Please replace the body of the lambda expression according to your needs.

请根据您的需要替换 lambda 表达式的主体。

Code on Ideone

Ideone 上的代码