如何使用以用户定义类型为键的 std::maps ?
我想知道为什么我不能将 STL 映射与用户定义的类一起使用。 当我编译下面的代码时,我收到以下神秘的错误消息。 这是什么意思? 另外,为什么它只发生在用户定义的类型上? (原始类型用作键时是可以的。)
C:\MinGW\bin..\lib\gcc\mingw32\3.4.5........\include\c++\3.4.5\bits\stl_function.h||中 成员函数`bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Class1]':|
C:\MinGW\bin..\lib\gcc\mingw32\3.4.5........\include\c++\3.4.5\bits\stl_map.h|338|实例化 来自`_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = Class1, _Tp = int, _Compare = std::less, _Alloc = std::allocator >]'|
C:\Users\Admin\Documents\dev\sandbox\sandbox\sandbox.cpp|24|实例化 从这里开始|
C:\MinGW\bin..\lib\gcc\mingw32\3.4.5........\include\c++\3.4.5\bits\stl_function.h|227|错误:不匹配对于“运算符<” 在 '__x <; __y'| ||=== 构建完成:1 个错误,0 个警告 ===|
#include <iostream>
#include <map>
using namespace std;
class Class1
{
public:
Class1(int id);
private:
int id;
};
Class1::Class1(int id): id(id)
{}
int main()
{
Class1 c1(1);
map< Class1 , int> c2int;
c2int[c1] = 12;
return 0;
}
I'm wondering why I can't use STL maps with user-defined classes. When I compile the code below, I get the following cryptic error message. What does it mean? Also, why is it only happening with user-defined types? (Primitive types are okay when they are used as key.)
C:\MinGW\bin..\lib\gcc\mingw32\3.4.5........\include\c++\3.4.5\bits\stl_function.h||In
member function `bool
std::less<_Tp>::operator()(const _Tp&,
const _Tp&) const [with _Tp =
Class1]':|C:\MinGW\bin..\lib\gcc\mingw32\3.4.5........\include\c++\3.4.5\bits\stl_map.h|338|instantiated
from `_Tp& std::map<_Key, _Tp,
_Compare, _Alloc>::operator[](const _Key&) [with _Key = Class1, _Tp = int, _Compare = std::less, _Alloc = std::allocator >]'|C:\Users\Admin\Documents\dev\sandbox\sandbox\sandbox.cpp|24|instantiated
from here|C:\MinGW\bin..\lib\gcc\mingw32\3.4.5........\include\c++\3.4.5\bits\stl_function.h|227|error: no match for 'operator<' in '__x <
__y'| ||=== Build finished: 1 errors, 0 warnings ===|
#include <iostream>
#include <map>
using namespace std;
class Class1
{
public:
Class1(int id);
private:
int id;
};
Class1::Class1(int id): id(id)
{}
int main()
{
Class1 c1(1);
map< Class1 , int> c2int;
c2int[c1] = 12;
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
实际上,您不必为您的类定义
operator<
。 您还可以为其创建一个比较器函数对象类,并使用它来专门化std::map
。 扩展您的示例:碰巧
std::map
的第三个模板参数的默认值是std::less
,它将委托给为您的类定义的operator<
(如果存在,则失败没有任何)。 但有时您希望对象可用作映射键,但实际上没有任何有意义的比较语义,因此您不想通过提供operator<
来迷惑人们> 就为了这个而在你的课堂上。 如果是这样的话,你可以使用上面的技巧。实现相同目的的另一种方法是专门化
std::less
:这样做的优点是它会被
std::map
“默认”选择,并且但您不会将operator<
暴露给客户端代码。You don't have to define
operator<
for your class, actually. You can also make a comparator function object class for it, and use that to specializestd::map
. To extend your example:It just so happens that the default for the third template parameter of
std::map
isstd::less
, which will delegate tooperator<
defined for your class (and fail if there is none). But sometimes you want objects to be usable as map keys, but you do not actually have any meaningful comparison semantics, and so you don't want to confuse people by providingoperator<
on your class just for that. If that's the case, you can use the above trick.Yet another way to achieve the same is to specialize
std::less
:The advantage of this is that it will be picked by
std::map
"by default", and yet you do not exposeoperator<
to client code otherwise.默认情况下
std::map
(和std::set
) 使用operator<
来确定排序。 因此,您需要在您的类上定义operator<
。两个对象被视为等价
if !(a < b) & & !(b < a)
。如果出于某种原因,您想使用不同的比较器,则可以将
map
的第三个模板参数更改为std::greater
。By default
std::map
(andstd::set
) useoperator<
to determine sorting. Therefore, you need to defineoperator<
on your class.Two objects are deemed equivalent
if !(a < b) && !(b < a)
.If, for some reason, you'd like to use a different comparator, the third template argument of the
map
can be changed, tostd::greater
, for example.您需要为 Class1 定义
运算符 <
。Map 需要使用运算符 < 来比较值 因此,当用户定义的类用作键时,您需要提供相同的内容。
You need to define
operator <
for the Class1.Map needs to compare the values using operator < and hence you need to provide the same when user defined class are used as key.
您的示例可以在 C++20 中运行 。
如果您只是添加到您的类中,
Your example works in C++20 if you just add
to your class.
我想稍微扩展一下 Pavel Minaev 答案,您应该先阅读该答案阅读我的答案。 如果要比较的成员(例如问题代码中的
id
)是私有的,Pavel 提出的两种解决方案都不会编译。 在这种情况下,VS2013 会抛出以下错误:正如 SkyWalker 在 对 Pavel 的回答进行评论,使用
friend
声明会有所帮助。 如果您想知道正确的语法,这里是:Ideone 上的代码
但是,如果您有以下访问功能您的私有成员,例如
id
的getId()
,如下所示:那么您可以使用它代替
friend
声明(即您比较lhs.getId() < rhs.getId()
)。从 C++11 开始,您还可以使用 lambda 表达式 用于 Pavel 第一个解决方案,而不是定义比较器函数对象类。
将所有内容放在一起,代码可以编写如下:
Code on Ideone
I'd like to expand a little bit on Pavel Minaev's answer, which you should read before reading my answer. Both solutions presented by Pavel won't compile if the member to be compared (such as
id
in the question's code) is private. In this case, VS2013 throws the following error for me:As mentioned by SkyWalker in the comments on Pavel's answer, using a
friend
declaration helps. If you wonder about the correct syntax, here it is:Code on Ideone
However, if you have an access function for your private member, for example
getId()
forid
, as follows:then you can use it instead of a
friend
declaration (i.e. you comparelhs.getId() < rhs.getId()
).Since C++11, you can also use a lambda expression for Pavel's first solution instead of defining a comparator function object class.
Putting everything together, the code could be written as follows:
Code on Ideone
键必须具有可比性,但您尚未为自定义类定义合适的
运算符<
。Keys must be comparable, but you haven't defined a suitable
operator<
for your custom class.正确的解决方案是为您的类/结构专门化
std::less
。• 基本上,cpp 中的映射是作为二叉搜索树实现的。
IE
BST 中的每个节点都包含元素,并且在映射的情况下其 KEY 和值,并且键应该是有序的。
有关地图实现的更多信息:地图数据类型。
在 cpp 映射的情况下,键是节点的元素,值不参与树的组织,它只是补充数据。
所以这意味着键应该与
std::less
或operator<
兼容,以便可以组织它们。 请检查地图参数。否则,如果您使用用户定义的数据类型作为键,则需要为该数据类型提供完整的比较语义。
解决方案:专门化
std::less
:地图模板中的第三个参数是可选的,它是
std::less
,它将委托给operator<
,因此为您的用户定义的数据类型创建一个新的
std::less
。 现在,这个新的std::less
将默认被std::map
选择。注意:您需要为每个用户定义的数据类型创建专门的
std::less
(如果您想使用该数据类型作为 cpp 映射的键)。错误的解决方案:
为您的用户定义的数据类型重载
运算符<
。这个解决方案也可以工作,但它非常糟糕,因为运算符
<
将为您的数据类型/类普遍重载。 这在客户端场景中是不可取的。请检查答案
The right solution is to Specialize
std::less
for your class/Struct.• Basically maps in cpp are implemented as Binary Search Trees.
i.e.
Every node in the BST contains Elements and in case of maps its KEY and a value, And keys are supposed to be ordered.
More About Map implementation : The Map data Type.
In case of cpp maps , keys are the elements of the nodes and values does not take part in the organization of the tree its just a supplementary data .
So It means keys should be compatible with
std::less
oroperator<
so that they can be organized. Please check map parameters.Else if you are using user defined data type as keys then need to give meaning full comparison semantics for that data type.
Solution : Specialize
std::less
:The third parameter in map template is optional and it is
std::less
which will delegate tooperator<
,So create a new
std::less
for your user defined data type. Now this newstd::less
will be picked bystd::map
by default.Note: You need to create specialized
std::less
for every user defined data type(if you want to use that data type as key for cpp maps).Bad Solution:
Overloading
operator<
for your user defined data type.This solution will also work but its very bad as operator
<
will be overloaded universally for your data type/class. which is undesirable in client scenarios.Please check answer Pavel Minaev's answer