删除给定行的注释后,我在代码中编译错误。我无法将结构插入到地图中,而插入整数很好。如何解决错误?
# include <iostream>
# include <map>
using namespace std;
struct node
{int test;}temp;
int main()
{
temp.test = 24;
int test = 30;
map < node, bool > mymap1;
map < int, bool > mymap2;
//mymap1.insert(make_pair(temp, true));
mymap2.insert(make_pair(test, true));
return 0;
}
答案 0 :(得分:11)
对于用作地图键的类型,必须订购。实际上,所有这些意味着必须为类型定义operator<
。如果您定义了全局operator<(const node&, const node&)
,这应该可以正常工作;即,
bool operator<(const node& n1, const node& n2) {
return n1.test < n2.test;
}
答案 1 :(得分:8)
std :: map的键内部存储在二叉搜索树中。为了在二叉搜索树中存储和搜索密钥,它们必须是可比较的。例如,二元搜索树的要求是左子项的键小于其父项的键,右子项的键大于其父项的键。但是,如果密钥不具有可比性,我们如何判断孩子是否比父母更大或更小?我们不能形成树,因此std :: map不适用于这些类型。
您只需要像这样定义小于运算符:
bool operator<(const node& n1, const node& n2)
{
return n1.test < n2.test;
}
如果“test”数据成员是私有的,那么它也必须是节点结构的朋友(因为节点当前是结构,所以它现在是公共的)。但是,我可能会这样做:
#include <map>
class node
{
public:
int getTest() const { return _test; }
void setTest(int test) { _test = test; }
private:
int _test;
};
bool operator<(const node& n1, const node& n2)
{
return n1.getTest() < n2.getTest();
}
int main()
{
std::map<node,bool> foo;
node n;
n.setTest(25);
foo[n] = true;
return 0;
}
答案 2 :(得分:1)
以下是阅读错误消息的方法:
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’:
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_tree.h:1141: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = node, _Val = std::pair<const node, bool>, _KeyOfValue = std::_Select1st<std::pair<const node, bool> >, _Compare = std::less<node>, _Alloc = std::allocator<std::pair<const node, bool> >]’
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_map.h:469: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = node, _Tp = bool, _Compare = std::less<node>, _Alloc = std::allocator<std::pair<const node, bool> >]’
prog.cpp:15: instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
首先,我们忽略大多数'实例化'行,因为他们只是讨论模板如何扩展。重要的是最后一个,指的是我们的源代码,因为它告诉我们错误被触发的位置。当然,无论如何我们都知道,所以我们也会跳过它。我们也会忽略有问题的库头的路径,因为我们并不关心编译器如何存储它的东西。
stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’:
stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
所以...我们的代码间接调用‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = node]’
,或者如果我们实际进行了替换,‘bool std::less<node>::operator()(const node&, const node&) const’
。这是一个问题,因为有no match for ‘operator<’ in ‘__x < __y’
。
__x
和__y
是std::less
实现中的变量(您应该可以猜到这么多)。从名称中我们可以猜测(如果我们已经研究过标准库,我们就会知道)std::less
是一个模板函数,它比较两个相同类型的东西,并返回第一个是否小于第二
它是如何做到的?当然,使用operator<
。所以我们需要做的就是解决问题:它说operator<
并不存在被比较的东西,所以我们必须提供它。有什么比较? node
,当然。所以我们为我们的班级定义operator<
。
为什么这样做?这样我们就可以编写接受比较操作作为参数的函数(模板参数或运行时参数 - 但前者更常见),并传递std::less
。这就是std::less
存在的原因:它将事物比较成一个函数,实际函数更有用。
这有什么关系?因为,就像其他人说的那样,std :: map实际上是以std::less
作为参数传递的。它实际上是std::map
模板的默认参数,用于比较元素。毕竟,地图界面的一部分是每个键都是唯一的。如果你无法比较它们,你将如何检查键的唯一性?当然,从技术上讲,你只需要比较它们的相同性即可。但事实证明,能够订购密钥可以创建更高效的数据结构。 (如果你真的参加了大学关于编程和CS的课程,你就会知道这一点。)
为什么int
没有问题?您现在应该可以猜到:operator<
已经自然适用于int
。但是你必须告诉C ++如何为任何用户类型做这件事,因为你可能还有别的想法。
答案 3 :(得分:0)
如Andrew Rasmussen's answer中所述,std::map
的键必须具有可比性。但是,您也可以为地图提供自定义比较对象,而不是为结构定义operator<
。此外,由于C++11,您可以使用lambda expression而不是定义比较对象。结果,您可以使代码简短,如下所示:
auto comp = [](const node& n1, const node& n2) { return n1.test < n2.test; };
std::map<node, bool, decltype(comp)> mymap1(comp);