45

I have the following code, but I get an error on on the last line:

struct coord { int x, y; bool operator=(const coord &o) { return x == o.x && y == o.y; } bool operator<(const coord &o) { return x < o.x || (x == o.x && y < o.y); } }; map<coord, int> m; pair<coord, int> p((coord{0,0}),123); m.insert(p); // ERROR here 

How can I use a struct as key in a map?


I tried to change the code to this:

struct coord { int x, y; bool const operator==(const coord &o) { return x == o.x && y == o.y; } bool const operator<(const coord &o) { return x < o.x || (x == o.x && y < o.y); } }; 

But I'm still getting the following error:

C:\Users\tomc\Desktop\g>mingw32-make g++ test.cpp -std=c++0x In file included from c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/string:5 0:0, from c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/loc ale_classes.h:42, from c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/ios _base.h:43, from c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/ios:43, from c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/ostream: 40, from c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/iostream :40, from test.cpp:1: c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_function.h: In member function 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _ Tp = coord]': c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_tree.h:1184:4: inst antiated from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = coord, _Val = std::pair<const coord, int>, _KeyOfValue = std::_Select1st<std:: pair<const coord, int> >, _Compare = std::less<coord>, _Alloc = std::allocator<std::pair<const coord, int>>]' c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_map.h:501:41: insta ntiated 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::map<_Key, _Tp, _Compare, _Alloc>::value_type>::other>::iterator, bool> std ::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::map<_Key, _Tp, _Compare, _ Alloc>::value_type&) [with _Key = coord, _Tp = int, _Compare = std::less<coord>, _Alloc = std::allocator<std::pair<const coord, int> >, typename std::_Rb_tree<_ Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _ Compare, typename _Alloc::rebind<std::map<_Key, _Tp, _Compare, _Alloc>::value_ty pe>::other>::iterator = std::_Rb_tree_iterator<std::pair<const coord, int> >, st d::map<_Key, _Tp, _Compare, _Alloc>::value_type = std::pair<const coord, int>]' test.cpp:56:12: instantiated from here c:\mingw\bin\../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_function.h:230:22: er ror: passing 'const coord' as 'this' argument of 'const bool coord::operator<(co nst coord&)' discards qualifiers mingw32-make: *** [game] Error 1 
5
  • 6
    What error do you get? Commented Aug 26, 2011 at 11:58
  • 3
    This isn't your problem but your operator= needs to be operator== Commented Aug 26, 2011 at 12:00
  • 4
    It should be bool operator<(const coord &o) const Commented Aug 26, 2011 at 12:07
  • 3
    const in the wrong place, after the argument list not before. What you did makes the return type const i.e. const bool, but you want to make the method const. Commented Aug 26, 2011 at 12:09
  • Read the Operator Overloading FAQ entry. In fact, this should be closed as a dupe, since it's all explained there. Commented Aug 26, 2011 at 12:27

4 Answers 4

64

Try and make operator < const:

bool operator<(const coord &o) const { 

(Your = operator should probably be == operator and const as well)

Sign up to request clarification or add additional context in comments.

3 Comments

Why adding const resolves the error , can you explain? , thanks
Actually, I'd make the operator a free function rather than a member function.
@x4: The key of a map is of type "const Key", so you can only perform operations on the struct that are marked as const. Trying to use methods that are not marked as const in that case results in the error above (using XXX discards qualifiers)
13

By far the simplest is to define a global "less than" operator for your struct in stead of as a member function.

std::map uses - by default - the 'lessthan' functor which, in turn, uses the global "operator<" defined for the key type of the map.

bool operator<(const coord& l, const coord& r) { return (l.x<r.x || (l.x==r.x && l.y<r.y)); } 

Comments

12

As mentioned in the answer by Andrii, you can provide a custom comparison object to the map instead of defining operator< for your struct. Since C++11, you can also use a lambda expression instead of defining a comparison object. Moreover, you don't need to define operator== for your struct to make the map work. As a result, you can keep your struct as short as this:

struct coord { int x, y; }; 

And the rest of your code could be written as follows:

auto comp = [](const coord& c1, const coord& c2){ return c1.x < c2.x || (c1.x == c2.x && c1.y < c2.y); }; std::map<coord, int, decltype(comp)> m(comp); 

Code on Ideone

Comments

2

Another solution, which may be used for third-party data types, is to pass a Comparison object as third template parameter. example

Comments