While overloading the operator<
for custom key in map
, why is const
required for both the argument and the function type?

- 171,901
- 28
- 288
- 402

- 91
- 8
-
Const reference means there are no extra copies of arguments and you can't accidentaly change them inside comparsion function – KIIV Jun 28 '16 at 17:35
-
You want to compare two const keys, you need two consts, one for each argument. – n. m. could be an AI Jun 28 '16 at 17:35
-
The `const` after the function means that the function does not modify the object on which the comparison is being done – smac89 Jun 28 '16 at 17:38
-
Possible duplicate of [Custom types as key for a map - C++](http://stackoverflow.com/questions/906244/custom-types-as-key-for-a-map-c) – chema989 Jun 28 '16 at 17:39
-
@chema989 Not so sure about that. That doesn't really explain why `const` is needed. – NathanOliver Jun 28 '16 at 17:41
4 Answers
The prototype for the operator< is
bool operator<(const Element& b) const { ..... }
const Element& b
means that extra copies of the element b are not created upon invocation of the operator<
as well as the arguments are not modified inside the method. The second const
means that the object on which the operator<
is called will not be modified upon this call invocation.

- 194
- 5
-
The second `const` just promises that the object on which the comparison is being done is not modified – smac89 Jun 28 '16 at 17:40
-
`operator<` has two prototypes, a non-member one and a member one. The more commonly used and recommended one is the non-member (for reasons too long to get into here), but you have cited the member prototype as "the" prototype. – Nir Friedman Jun 28 '16 at 17:43
As I understand, const reference
for argument type serves 2 purposes:
- From the signature it tells that, the argument is non-modifiable inside the function body and any such adventures would yield to compiler errors.
- There is no extra unnecessary copying of the
key
type.
The member function is made const
so that you can still do a find
(or any other pure read (unless modifying a mutable
member) operation) call on a const
map object. Without that const, on trying to invoke those member functions on a const map object, it would lead to a compilation error.
A const
for a global or non-member function is not required when you are trying to create a custom comparison function.
bool operator<(const Key& a, const Key& b) /* no const required here*/ {....}
const
for a function is only applicable to member functions as it makes the this
pointer or instance a const
which cannot be the case for global or non-member comparison operators
The value_type for an std::map<K, V>
is not std::pair<K, V>
as you might think, but actually std::pair<const K, V>
. Therefore, any comparison invoked on the keys deals with const objects.
Now when the compiler sees
a < b
and at least one of a
or b
is of user-defined type, the compiler calls either
operator < (a, b); //(1)
or
a.operator < (b); //(2)
(if both of these are available, an error is issued).
A non-constant member-function, including any operator, can only be invoked on non-constant objects. So, because a
is constant, it is required that in case of //2
the function be declared const. Since b
is constant too, the parameter must be a const reference, because non-const references cannot be bound to constant objects. Hence the requirement for both consts.
The parameter has another option apart from being const. It could take the parameter by value, but that would mean unnecessary copying. Similarly, if you chose to declare a non-member operator <
, you should take both parameters either by const reference (recommended) or by value.

- 130,161
- 59
- 324
- 434
Const in an argument is function promising its caller to not modify the argument that is passed in. It is often needed when argument is passed by reference to avoid an extra copy but is not going to be modified, for example:
void function(const Type& var)
{
// can't modify var here, but can read and call its const methods (see below)
}
Const in the method declaration is method promising not to modify internal state of the object it is called on. For example
void Class::function(const Type& var) const
{
// can't modify var here
// can't modify "this" here (call other non const methods or change member variables)
}
Those promises can be broken (this is C++ we are talking about after all) by casting constness away, but that is the intent anyway.
It is good idea to always ask for as little as you need. If method doesn't change an object -- declare it as const, then you can call this method on a const instance of that class (for example when it was passed as a const reference somewhere else).
In case of custom operator <
on std::map, the reason you can't use non-const reference in arguments is because std::map will call your operator inside one or more of its own methods, and they might be declared const themselves. Compiler will not allow it to pass const object into function that doesn't promise not to modify it.
The reason you can't declare operator <
itself non const (assuming it is not a free standing function, but a method of your custom class used as a key) is the same -- std::map already promised not to modify the key (that would wreak havoc in sort ordering for one), so it can't call any method on it that doesn't promise the same.
Custom operator <
when used for sorting inside containers also has other requirements -- it must satisfy LessThanComparable concept.