views:

313

answers:

3

Hi everyone. I have a small program I want to execute to test something

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

The problem is that when I try to compile it, I get the following error

$ 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 for ‘operator<’ in ‘__x < __y’
m2.cpp:9: note: candidates are: bool _pos::operator<(_pos&)
$ 

I thought that declaring the operator< on the key would solve the problem, but its still there.

What could be wrong?

Thanks in advance.

+3  A: 

Signature of the less than operator needs to be bool operator<(const _pos& other) const, otherwise map can not use this operator in const functions since this member function is declared as non-const.

Naveen
+14  A: 

The problem is this:

bool operator<(_pos& other)

Should be this:

bool operator<(const _pos& other) const {
//             ^^^^               ^^^^^

Without the first const, the right-hand side of the comparison (b in a < b) cannot be const, since without const the function may modify its argument.

Without the second const, the left-hand side of the comparison (a in a < b) cannot be const, since without const the function may modify this.

Internally, the key's of a map are always const.


It should be noted that you should prefer to use nonmember functions. That is, better is a free-function:

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

In the same namespace as your class. (For our example, just underneath it.)


By the way, in C++ there is no need to prefix the declaration of a struct type variable with struct. This is perfect, and preferred:

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

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

(Though your type names are admittedly named in an unorthodox manner. :P)


Lastly, you should prefer the make_pair utility function for making pairs:

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

It saves you from having to write out the types for the pair, and is generally easier to read. (Especially when longer type names come along.)

GMan
Thanks for the extra tip.
Tom
@Tom: No problem, I've added more. :P
GMan
In this case, subscript notation is probably neater than using insert directly: `m[k1]=v1; m[k2]=v2;`.
Jerry Coffin
I would note that the subscript operator and the insert operation have different semantics in case the element is already present: subscript replaces it while insert does not. *They are not interchangeable* in general! Also, insert works with other containers (`set` for example) while the subscript operator is very specific to associative containers like `map`.
Matthieu M.
+3  A: 

I think that your definition of operator< is wrong - the right hand side (argument in this case) should be marked const and it should be a const member function, e.g.

    bool operator<(const _pos& other) const{ 

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