是否不可能将 STL 映射与结构体作为键一起使用?

发布于 2024-08-20 03:50:00 字数 280 浏览 9 评论 0 原文

我有以下代码:

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 时,出现编译错误。为什么?

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 Node to an int, I got a compile error. Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

oО清风挽发oО 2024-08-27 03:50:01

如果您确实不需要按键对数据进行排序,则可以使用新的 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 毕竟更容易使用。

If you don't really need to have your data sorted by key, you can use the new 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.

UPDATE
As Neil points out you need an specialized hash function if you want an unordered_map with Node keys.

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:

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.

溺渁∝ 2024-08-27 03:50:01

您能否发布编译器错误 - 他们的目的是告诉出了什么问题

我猜您会发生错误,因为 Node 没有实现地图所需的比较运算符来识别其元素。

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

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

英雄似剑 2024-08-27 03:50:01

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

输出:

2、3:1

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

Ideone 上的代码

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

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

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

Code on Ideone

拥抱我好吗 2024-08-27 03:50:00

对于可用作映射中的键的事物,您必须能够使用operator<() 对其进行比较。您需要将这样的运算符添加到节点类中:

struct Node
{
 int a;
 int b;

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

当然,真正的运算符的作用取决于比较对您的结构的实际含义。

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:

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.

故事未完 2024-08-27 03:50:00

您必须告诉 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 对,映射将考虑 x 和y 相等(相同的键)。

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.

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).

羁拥 2024-08-27 03:50:00

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

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 类),并且有利于实现更具可扩展性的解决方案。

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

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 Comparable mean for a user-defined type.

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 Node class. This makes it possible to define maps specialised with different comparison conditions (functors).

#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::a another comparing both components, Node::a and Node::b. Then, defined different types of maps:

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文