std::map和std::pair存在问题

9

我有一个小程序需要执行来测试某些东西

#include <map>
#include <iostream>
using namespace std;

struct _pos{
        float xi;
        float xf;

        bool operator<(_pos& other){

                return this->xi < other.xi;
        }
};

struct _val{

        float f;
};

int main()
{
        map<_pos,_val> m;

        struct  _pos k1 = {0,10};
        struct  _pos k2 = {10,15};

        struct  _val v1 = {5.5};
        struct  _val v2 = {12.3};                                                                   

        m.insert(std::pair<_pos,_val>(k1,v1));
        m.insert(std::pair<_pos,_val>(k2,v2));

        return 0;
}

问题在于当我尝试编译它时,出现以下错误。
$ g++ m2.cpp -o mtest
In file included from /usr/include/c++/4.4/bits/stl_tree.h:64,
                 from /usr/include/c++/4.4/map:60,
                 from m2.cpp:1:
/usr/include/c++/4.4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = _pos]’:
/usr/include/c++/4.4/bits/stl_tree.h:1170:   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 = _pos, _Val = std::pair<const _pos, _val>, _KeyOfValue = std::_Select1st<std::pair<const _pos, _val> >, _Compare = std::less<_pos>, _Alloc = std::allocator<std::pair<const _pos, _val> >]’
/usr/include/c++/4.4/bits/stl_map.h:500:   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 = _pos, _Tp = _val, _Compare = std::less<_pos>, _Alloc = std::allocator<std::pair<const _pos, _val> >]’
m2.cpp:30:   instantiated from here
/usr/include/c++/4.4/bits/stl_function.h:230: error: no match foroperator<’ in ‘__x < __y’
m2.cpp:9: note: candidates are: bool _pos::operator<(_pos&)
$ 

我曾认为在键上声明operator<可以解决问题,但问题仍然存在。

可能出了什么问题?

提前感谢您的帮助。


5
在C++中,以两个下划线开头、下划线后跟大写字母或下划线后跟小写字母的全局命名空间标识符都被保留给实现。"_pos"和"_val"这些标识符应该更改。 - David Rodríguez - dribeas
@David Rodríguez。谢谢,会的,记住了。 - Tom
3个回答

25

问题是这样的:

bool operator<(_pos& other)
应该是这样的:
bool operator<(const _pos& other) const {
//             ^^^^               ^^^^^

如果没有第一个const,则比较运算符右侧的值(a < b中的b)无法被声明为const,因为如果没有const,函数可能会修改其参数。

如果没有第二个const,则比较运算符左侧的值(a < b中的a)无法被声明为const,因为如果没有const,函数可能会修改this

在内部,Map的键始终是const


应该注意,更好的做法是使用非成员函数。也就是说,一个自由函数是更好的:

bool operator<(const _pos& lhs, const _pos& rhs)
{
    return lhs.xi < rhs.xi;
}

在与您的类相同的命名空间中。(对于我们的示例,就在其下方。)


顺便说一句,在C++中,不需要在结构体类型变量的声明前加上struct前缀。这是完美的,也是首选:

    _pos k1 = {0,10};
    _pos k2 = {10,15};

    _val v1 = {5.5};
    _val v2 = {12.3};

虽然你的类型名称命名方式有些不寻常。:P


最后,你应该优先使用make_pair实用函数来创建pair:

    m.insert(std::make_pair(k1,v1));
    m.insert(std::make_pair(k2,v2));

使用pair的好处是可以省略类型声明,这样通常更易于阅读。(特别是当类型名称较长时。)


@Tom:没问题,我已经加了更多。 :P - GManNickG
在这种情况下,使用下标符号可能比直接使用插入更整洁:m[k1]=v1; m[k2]=v2; - Jerry Coffin
1
请注意,如果元素已经存在,则下标运算符和插入操作具有不同的语义:下标运算符将其替换,而插入操作则不会。总的来说,它们不能通用!此外,插入操作适用于其他容器(例如set),而下标运算符非常特定于关联式容器(如map)。 - Matthieu M.

5

小于运算符的签名需要是bool operator<(const _pos& other) const,否则map无法在常量函数中使用此运算符,因为该成员函数被声明为非常量。


4

我认为你对 operator< 的定义是错误的 - 此时右侧(参数)应该被标记为 const,而且它应该是一个 const 成员函数,例如:

    bool operator<(const _pos& other) const{ 

            return this->xi < other.xi; 
    } 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接