2

Possible Duplicate:
What requirements must std::map key classes meet to be valid keys?

I want to use std::map as map from my class to another one. If I try the following code, I get an error "undefined operator <". Does it mean that I need an ordering on class K to use map? And does it have to be full ordering? And do I need all four ordering operators or > is enough?

#include <iostream>
#include <map>
#include <stdio.h>
using namespace std;

struct K {
    int i, j;

    K(int i, int j) : i(i), j(j){}

    friend bool operator==(const K& x, const K& y){ return (x.i==y.i)&&(x.j==y.j); }
    friend bool operator!=(const K& x, const K& y){ return !(x==y); }

/*  friend bool operator<(const K&x, const K&y){
        if(x.i<y.i) return true;
        if(x.i>y.i) return false;
        return x.j<y.j;
    }
    friend bool operator>(const K&x, const K&y){ return y<x; }
    friend bool operator<=(const K&x, const K&y){ return !(y<x); }
    friend bool operator>=(const K&x, const K&y){ return !(x<y); }
*/
};


int main(){
    map<K, float> m;
    m[K(1,2)]=5.4;
    if(m.find(K(1,2))!=m.end())
        cout << "Found: " << m[K(1,2)] << endl;
    else
        cout << "Not found" << endl;
    return 0;
}
Community
  • 1
  • 1
yo'
  • 811
  • 11
  • 22
  • You only need `operator<`, i.e. `operator<=`, `operator>` etc. are not required. Is that what you mean by full ordering? (And actually, if you don't want to code an `operator<`, you may pass a comparator function as third template argument.) – jogojapan Oct 16 '12 at 13:36
  • full = linear, i.e. always exactly one of `x>y`, `y>x` or `x==y` hold. – yo' Oct 16 '12 at 13:38
  • Oh, a _total_ ordering. No, actually, it's a strict weak ordering, same as what is described here: http://stackoverflow.com/a/12419851/777186 – jogojapan Oct 16 '12 at 13:40
  • Elements in a map must follow a [strict weak ordering](http://en.wikipedia.org/wiki/Strict_weak_ordering) – MadScientist Oct 16 '12 at 13:40
  • so `operator>(const Q& x, const Q& y){return false;}` would suffice? – yo' Oct 16 '12 at 13:41
  • No, `operator<`. Nothing will ever look for any other. – Jan Hudec Oct 16 '12 at 13:41
  • @JanHudec I'm sorry, I meant that of course. – yo' Oct 16 '12 at 13:49
  • 2
    IF this is your real code, then use `std::pair` instead of `K` - `std::pair` has all you need to use it as key in `map` – PiotrNycz Oct 16 '12 at 13:52
  • @PiotrNycz No, it is not. My real code is a template class with 3 parameters, one of them usually another template class. Simply too much unrelated stuff. – yo' Oct 16 '12 at 13:54

4 Answers4

5

Yes, you need a way to compare elements (operator<) in order to use the std::map. One of the features of map is that it keeps its contents in sorted order, but to achieve this its need to know how to compare items.

You have three options to implement a comparison method:

  1. Add operator< definition in K
  2. Make a comp functor that know to how to compare two K elements and add this as a template parametermap<K, float, comp> m;

    struct comp {
        bool operator()(const K& first, const K& second) {
            /*****/
        }
    };
    
  3. You can define the std::less specialization for K

    template<>  struct less<K>
    {
        bool operator()(const K& first, const K& second) {
            /*****/
        }
    };
    

And simple use map<K, float> m;

This works because by the template definition for map has the compare function set to std::less.

template < class Key, class T, class Compare = less, class Allocator = allocator > > class map

andre
  • 7,018
  • 4
  • 43
  • 75
4

The elements in your map are referenced by a comparison function on the Key type you supply. Either implicitly as std::less or explicitly as third template argument.

If you use a custom key type, you also need to supply an appropriate comparison function (or functional object) that imposes a strict weak ordering on the keys. That is, if the keys appear equal

!(key1 < key2 || key2 < key1)

the items are considered equivalent.

Thus, if your comparison function only provides a partial order on the keys, elements may be considered equal that actually are different, and thereby their values might interfere with each other.

moooeeeep
  • 31,622
  • 22
  • 98
  • 187
0

Just define operator<

Everything else is unnecessary for the purpose of std::map ordering.

Component 10
  • 10,247
  • 7
  • 47
  • 64
-2

An std::map needs simply an operator<. Implementations usually employ a "red-black" tree which can be built to only requires a < operator.

However you can use std::unordered_map exactly how you just did. It typically uses a generic hash function; you are free to supply your own hash function for it if suits your problem-space since C++11.

std''OrgnlDave
  • 3,912
  • 1
  • 25
  • 34
  • -1: `std::map` defaults to `operator<` since SGI initially designed STL! It never needed it and still does not need it. – Jan Hudec Oct 16 '12 at 13:42
  • @jogojapan I'm confused? I hit post and it had 2 downvotes? I suggested an unordered map right in the body... – std''OrgnlDave Oct 16 '12 at 13:45
  • @Robᵩ I think there was an error. As you see there aren't any edits to the answer, but it doesn't say what you said it does. I am very confused by this :-\ – std''OrgnlDave Oct 16 '12 at 13:45
  • How the heck did I get downvoted before I even post a question? – std''OrgnlDave Oct 16 '12 at 13:47
  • Rewriting all of the body once you hit "post" is a bad idea. The answer gets immediately loaded for people who have the question open and they start commenting. Better delete it and write the correct answer. – Jan Hudec Oct 16 '12 at 13:47
  • @JanHudec There aren't any edits though! See no "last edited" line? This is weird! – std''OrgnlDave Oct 16 '12 at 13:49
  • 1
    @std''OrgnlDave - You hit post before you finished typing, then clicked edit. SO treats edits that happen fairly immediately as the original post. – Robᵩ Oct 16 '12 at 13:51
  • Yes, that stack exchange feature is really weird. It collapses edits made within 5 minutes, but that is more than enough for people to comment and than the comments make no sense, because the commented version does not exist at all. – Jan Hudec Oct 16 '12 at 13:51
  • I would swear on my life I didn't hit edit, but then if I made such a careless mistake as the comments noted, perhaps my mind is playing tricks on me. – std''OrgnlDave Oct 16 '12 at 13:53
  • @JanHudec Also, SGI didn't design STL. It was designed by Alexander Stepanov and Meng Lee, and the first report on it was a paper from HP. SGI just released a famous version of it. – std''OrgnlDave Oct 16 '12 at 13:54