8

From http://www.cplusplus.com/reference/map/map/operators/ I noticed:

"Notice that none of these operations take into consideration the internal comparison object of either container, but compare the elements (of type value_type) directly."

this is to say that the overloaded operator "<" is not using the Compare in its declaration (refer to http://www.cplusplus.com/reference/map/map/)

std::map
template < class Key,                                     // map::key_type
           class T,                                       // map::mapped_type
           class Compare = less<Key>,                     // map::key_compare
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
           > class map;

where the Compare is

Compare: A binary predicate that takes two element keys as arguments and returns a bool. The expression comp(a,b), where comp is an object of this type and a and b are key values, shall return true if a is considered to go before b in the strict weak ordering the function defines. The map object uses this expression to determine both the order the elements follow in the container and whether two element keys are equivalent (by comparing them reflexively: they are equivalent if !comp(a,b) && !comp(b,a)). No two elements in a map container can have equivalent keys. This can be a function pointer or a function object (see constructor for an example). This defaults to less<T>, which returns the same as applying the less-than operator (a<b). Aliased as member type map::key_compare.

I don't quite understand it, why not just use Compare in the "<" operator?

David G
  • 94,763
  • 41
  • 167
  • 253
athos
  • 6,120
  • 5
  • 51
  • 95
  • Maybe the idea was that `<` should use `<`, but I would sure like to hear a less guessy response. – Angew is no longer proud of SO Jan 06 '15 at 14:16
  • (in gcc), they explicitly call `lexicographical_compare`, I don't see why they don't simply propgate the compare function to this, as far as I can see, it's available... My guess would be that the `Compare` function can be arbitrarily complex, and for this case, it's only interested in whether the element at the same location is the same, so a simpler `<` could be more efficient - but it's a guess... – Nim Jan 06 '15 at 14:21
  • @Nim presumably if they propagated the `Compare` functor then the behaviour would deviate from something specified in the standard. – juanchopanza Jan 06 '15 at 14:42

2 Answers2

4

Compare is for comparing key_type. The map's < operator is actually comparing mapped_type value_type, not key_type, so Compare would not be applicable. value_type is the pair of key_type and mapped_type.

To be honest, though, I think giving map an operator< in the first place is a case of operator overloading gone too far. It's not immediately obvious what is means to say one map is "less than" another. If you want lexigraphical_compare, I'd recommend calling it directly, or at least documenting in your code what your map comparison means.

Joel
  • 449
  • 3
  • 5
  • do you mean `Compare` is comparing `key_type`, while `<` is comparing `map::mapped_type`? I don't get you... – athos Jan 06 '15 at 14:43
  • 1
    `Compare` is used internally in order to sort the keys of a given map (used so that looking up keys can be done in O(lg n) and also allowing things like `std::lower_bound` to work). The `operator<` of the map is used to compare two maps to each other. – Karl Knechtel Jan 06 '15 at 14:52
  • Typically one would expect comparisons to make sense only between objects of the same type. Two maps with different `compare` functions, seem like two different types to me. If they used the same `compare` function, it might make sense to use it as a `<` operator. But I don't know if it is possible to decide at compile time if the `compare` functions are the same. – Arun R Jan 06 '15 at 15:35
  • Edited to be more explicit about key_type vs mapped_type – Joel Jan 06 '15 at 15:42
  • @ArunR Two maps of the same type can have completely different orderings. See my answer. – juanchopanza Jan 06 '15 at 15:50
  • @juanchopanza: There may be duplicate keys between the two maps being compared, in which case the elements would be compared. – Joel Jan 06 '15 at 16:19
3

Why std::map overloaded operator < does not use the Compare

A very good reason is that it would not be easy to ensure behaviour that makes sense. Given that the Compare functor can be stateful, two maps of the same type could have completely different ordering criteria. For example,

struct Cmp
{
  Comp(bool flip) : flip(flip) {}

  bool operator()(int lhs, int rhs) const
  {
    return flip ? lhs < rhs : rhs < lhs;
  }

  bool flip;
};

These two maps have the same type, but different ordering:

std::map<int, std::string, Cmp> m0(Cmp(false));
std::map<int, std::string, Cmp> m1(Cmp(true));

bool b = m0 < m1; // which Cmp should this use?

This is not necessarily a reason for using < etc, but a good reason not to use Compare.

Nikko
  • 4,182
  • 1
  • 26
  • 44
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • The `flip` here might be a bit rare but I agree that `<` can behave differently during string comparison, whether case sensitive or not... i think i get it. – athos Jan 06 '15 at 14:56
  • @athos The point is that two functors of the same type can have different behaviour. This artificial example is just to illustrate that. – juanchopanza Jan 06 '15 at 14:57