c++comparatorstd-algorithm

Why do I need to add 'const' in the custom comparator?


I am not very familiar with C++, and am confused about how a comparator works.

The below code is how I can find the position I want to insert a new interval:

#include <algorithm>
#include <vector> 

using namespace std;

int main()
{
    vector<vector<int>> intervals; // = ...
    vector<int> newInterval;       // = ...
    // ...

    auto comp = [](const vector<int>& a, const vector<int>& b) { return a[0] < b[0]; };
    auto it = upper_bound(intervals.begin(), intervals.end(), newInterval, comp);
}

Hen I try to remove const, it will get a compile error.

Why do I need to add const for this custom comparator?


Solution

  • From the std::upper_bound documentation regarding the comparator (comp):

    The signature of the predicate function should be equivalent to the following:

    bool pred(const Type1 &a, const Type2 &b);

    While the signature does not need to have const &, the function must not modify the objects passed to it and must be able to accept all values of type (possibly const).
    (thus, Type1 & is not allowed, nor is Type1 unless for Type1 a move is equivalent to a copy(since C++11))

    (emphasis is mine)

    Since the comparator must be able to accept const values (and must not modify them), the trivial solution is to use const &. The other alternative is to accept the objects by value, which is relevant only for simple types like int.

    Note:

    As @IgorTandetnik commented in practice only the first object must be const, in all 3 major compilers (gcc, clang, MSVC) - see demo. But this is true only in the case that non-const iterators are used (like in the code you posted). If you use const iterators (cbegin(), cend()) both objects in the comparators must be const in order to compile.

    In any case it's good practice to have a const & for both objects in the comparator.