std::max(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– NAME πŸ’–

std::max β€” okay so it's literally just std::max, bestie. That's the whole name. It lives in the C++ Standard Library (like, the (3) up in the corner is the manual section, don't worry about it), and it does exactly one thing: it tells you which of your values is the bigger one. Iconic. No cap.


✨ Synopsis ✨

It's defined in the header <algorithm> β€” write that down, you will forget it 🌸

template< class T >                                    (1) (constexpr since C++14)
const T& max( const T& a, const T& b );

template< class T, class Compare >                     (2) (constexpr since C++14)
const T& max( const T& a, const T& b, Compare comp );

template< class T >                                    (3) (since C++11)
T max( std::initializer_list<T> ilist );                   (constexpr since C++14)

template< class T, class Compare >                     (4) (since C++11)
T max( std::initializer_list<T> ilist, Compare comp );     (constexpr since C++14)

So basically: returns the greater of the given values 🫢

  • 1, 2) Returns the greater of a and b.
    • 1) Uses operator< to compare the values. If T is not LessThanComparable, the behavior is undefined 😭 (like, don't, fr).
    • 2) Uses the comparison function comp to compare the values.
  • 3, 4) Returns the greatest of the values in initializer list ilist. If ilist.size() is zero, or T is not CopyConstructible, the behavior is undefined πŸ’€
    • 3) Uses operator< to compare the values. If T is not LessThanComparable, the behavior is undefined.
    • 4) Uses the comparison function comp to compare the values.

πŸŽ€ Parameters πŸŽ€

  • a, b β€” the values to compare πŸ’…
  • ilist β€” initializer list with the values to compare
  • comp β€” comparison function object (i.e. an object that satisfies the requirements of Compare) which returns true if a is less than b.

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

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

Okay so about comp, and this part is lowkey a lot but it matters πŸ‘‘: while the signature does not need to have const&, the function must not modify the objects passed to it, and it must be able to accept all values of type (possibly const) Type1 and Type2 regardless of value category (thus, Type1& is not allowed, nor is Type1 unless for Type1 a move is equivalent to a copy (since C++11)). The types Type1 and Type2 must be such that an object of type T can be implicitly converted to both of them.


🌈 Return value 🌈

  • 1, 2) The greater of a and b. If they are equivalent, returns a. (Tie goes to a, that's just the rules πŸ’–)
  • 3, 4) The greatest value in ilist. If several values are equivalent to the greatest, returns the leftmost one.

⭐ Complexity ⭐

Given N as ilist.size():

  • 1) Exactly one comparison using operator<.
  • 2) Exactly one application of the comparison function comp.
  • 3) Exactly N-1 comparisons using operator<.
  • 4) Exactly N-1 applications of the comparison function comp.

Like, it is so efficient. It ate and left no crumbs πŸ”₯


🧚 Possible implementation 🧚

max (1)

template<class T>
const T& max(const T& a, const T& b)
{
    return (a < b) ? b : a;
}

max (2)

template<class T, class Compare>
const T& max(const T& a, const T& b, Compare comp)
{
    return (comp(a, b)) ? b : a;
}

max (3)

template<class T>
T max(std::initializer_list<T> ilist)
{
    return *std::max_element(ilist.begin(), ilist.end());
}

max (4)

template<class T, class Compare>
T max(std::initializer_list<T> ilist, Compare comp)
{
    return *std::max_element(ilist.begin(), ilist.end(), comp);
}

πŸ¦‹ Notes πŸ¦‹

⚠️ Okay this is the important one, bestie: capturing the result of std::max by reference produces a dangling reference if one of the parameters is a temporary and that parameter is returned. Like:
int n = -1;
const int& r = std::max(n + 2, n * 2); // r is dangling

Not me warning you and you still doing it 😭 Just don't hold a reference to a temporary. Periodt.


🌸 Example 🌸

// Run this code

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <string_view>

int main()
{
    auto longest = [](const std::string_view s1, const std::string_view s2)
                   {
                       return s1.size() < s2.size();
                   };

    std::cout << "Larger of 69 and 96 is " << std::max(69, 96) << "\n"
                 "Larger of 'q' and 'p' is '" << std::max('q', 'p') << "'\n"
                 "Largest of 010, 10, 0X10, and 0B10 is "
              << std::max({010, 10, 0X10, 0B10}) << '\n'
              << R"(Longest of "long", "short", and "int" is )"
              << std::quoted(std::max({"long", "short", "int"}, longest)) << '\n';
}

Output

Larger of 69 and 96 is 96
Larger of 'q' and 'p' is 'q'
Largest of 010, 10, 0X10, and 0B10 is 16
Longest of "long", "short", and "int" is "short"

(Yes, 010 and 0X10 are octal and hex, that's why you get 16 β€” the vibe check passed πŸ™ˆ)


πŸ’œ Defect reports πŸ’œ

The following behavior-changing defect reports were applied retroactively to previously published C++ standards. (History being rewritten, main character energy πŸ‘‘)

  • DR LWG 281, applied to C++98: behavior as published was that T was required to be CopyConstructible for overloads (1, 2) β€” correct behavior: not required. Slay, they fixed it ✨

πŸ“ See also πŸ“

  • min β€” returns the smaller of the given values (function template)
  • minmax (C++11) β€” returns the smaller and larger of two elements (function template)
  • max_element β€” returns the largest element in a range (function template)
  • clamp (C++17) β€” clamps a value between a pair of boundary values (function template)
  • ranges::max (C++20) β€” returns the greater of the given values (niebloid)

That's the whole page, bestie, go forth and compare things πŸ’…βœ¨

Signing off with the source, the version and the date so you can cite me properly: this came from http://cppreference.com, version 2024.06.10, dated 2024.06.10 β€” manual page std::max(3), mwah πŸ«ΆπŸŽ€

πŸ“¦ where this page comes from