Search code examples
c++maxmincomparison-operators

Confusion regarding comparison operators in std::min, std::max


std::min and std::max allows custom comparators, but I am a bit confused on how the ordering works.

Consider the following:

   int i = 1;
   int j = 2;

   auto min_val = min(i, j, [](const auto val1, const auto val2){
      if(val1 < val2) return true;
      return false;
   });

This returns the minimum value, which is i. But I don't understand why we use the < instead of the >, and why val1 and val2 appear on the left and right of the operand, respectively.

Consider the following:

   int i = 1;
   int j = 2;

   auto max_val = max(i, j, [](const auto val1, const auto val2){
      if(val1 > val2) return true;
      return false;
   });

I was thinking that this would return the maximum value, but it actually returns the minimum value, and again, we must use the < operand. Could someone explain what is going on beneath the hood?

I've run into this issue on some other stuff too, I think with std::priority_queue and std::map, where the ordering and comparison operators aren't very intuitive to me, and most times I have to guess and check to get what I want.


Solution

  • That basically boils down to how those functions are defined in the standard. std::max, for example, defines the comparer (your lambda) as follows:

    comparison function object (i.e. an object that satisfies the requirements of Compare) which returns ​true if a is less than b.

    Usually, when it comes to the order of values within the c++ standard library, it's (almost?) always std::less that is used as a default comparer, which does exactly left < right.

    As to why it's always a < b that has to be satisfied I think it's simply to reduce coding overhead if you were to write it yourself. Imagine having a comparer like this:

    struct MyComp
    {
        bool operator()(MyType a, MyType b) const
        {
            return a.getValue() < b.getValue();
        }
    };
    

    Since all the constructs in the standard library require your comparer to return true, if a < b, you can use one simple comparer for a multitude of constructs. E.g.

    auto maxVal = std::max(a, b, MyComp{});
    auto minVal = std::min(a, b, MyComp{});
    std::map<MyType, MyComp> myMap;
    

    will all just work with one comparer.