std::cmp_eq...eater_equal(3)
π std::cmp_equal, cmp_not_equal, cmp_less, cmp_greater, cmp_less_equal, cmp_greater_equal π
okay so bestie, we're in the C++ Standard Library section of the manual (that's the manual name, mwah) and today we're talking about the single most underrated glow-up in C++20: the cmp_* family. no cap, these little icons fix the one thing that has been embarrassing signed/unsigned math since forever.
β¨ NAME β¨
std::cmp_equal, cmp_not_equal, cmp_less, cmp_greater, cmp_less_equal, cmp_greater_equal β like, all six of them, together, holding hands π«Ά
πΈ Synopsis πΈ
Defined in header <utility>:
template< class T, class U > (1) (since C++20)
constexpr bool cmp_equal( T t, U u ) noexcept;
template< class T, class U > (2) (since C++20)
constexpr bool cmp_not_equal( T t, U u ) noexcept;
template< class T, class U > (3) (since C++20)
constexpr bool cmp_less( T t, U u ) noexcept;
template< class T, class U > (4) (since C++20)
constexpr bool cmp_greater( T t, U u ) noexcept;
template< class T, class U > (5) (since C++20)
constexpr bool cmp_less_equal( T t, U u ) noexcept;
template< class T, class U > (6) (since C++20)
constexpr bool cmp_greater_equal( T t, U u ) noexcept;
So the whole vibe is: compare the values of two integers t and u. π
But here's the tea β unlike builtin comparison operators, negative signed integers always compare less than (and not equal to) unsigned integers. the comparison is safe against non-value-preserving integer conversion. it's giving "finally, someone with common sense".
-1 > 0u; // true
std::cmp_greater(-1, 0u); // false
and yeah β it is a compile-time error if either T or U is a non-integer type, a character type, or bool. so don't even try it π
π Parameters π
tβ left-hand argumentuβ right-hand argument
(like, the two things you're comparing. that's it. that's the parameter list π)
β Return value β
trueiftis equal tou.trueiftis not equal tou.trueiftis less thanu.trueiftis greater thanu.trueiftis less or equal tou.trueiftis greater or equal tou.
literally just yes/no energy for each of the six π¦
π§ Possible implementation π§
the "if you're nosy, here's how the sausage gets made" section. obsessed.
template<class T, class U>
constexpr bool cmp_equal(T t, U u) noexcept
{
if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
return t == u;
else if constexpr (std::is_signed_v<T>)
return t >= 0 && std::make_unsigned_t<T>(t) == u;
else
return u >= 0 && std::make_unsigned_t<U>(u) == t;
}
template<class T, class U>
constexpr bool cmp_not_equal(T t, U u) noexcept
{
return !cmp_equal(t, u);
}
template<class T, class U>
constexpr bool cmp_less(T t, U u) noexcept
{
if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
return t < u;
else if constexpr (std::is_signed_v<T>)
return t < 0 || std::make_unsigned_t<T>(t) < u;
else
return u >= 0 && t < std::make_unsigned_t<U>(u);
}
template<class T, class U>
constexpr bool cmp_greater(T t, U u) noexcept
{
return cmp_less(u, t);
}
template<class T, class U>
constexpr bool cmp_less_equal(T t, U u) noexcept
{
return !cmp_less(u, t);
}
template<class T, class U>
constexpr bool cmp_greater_equal(T t, U u) noexcept
{
return !cmp_less(t, u);
}
π Notes π
okay important disclaimer bestie: these functions cannot be used to compare enums (including std::byte), char, char8_t, char16_t, char32_t, wchar_t and bool. that's a hard no. β
also there's a feature-test macro if you're into that:
- Feature-test macro:
__cpp_lib_integer_comparison_functions - Value:
202002L - Std:
(C++20) - Feature: Integer comparison functions
π₯ Example π₯
so the example below might produce a different signedness comparison warning if compiled without an appropriate warning suppression flag, e.g., -Wno-sign-compare (gcc/clang with -Wall -Wextra, see also SO: disabling a specific warning). consider yourself warned, diva.
// Run this code
#include <utility>
// Uncommenting the next line will disable "signed/unsigned comparison" warnings:
// #pragma GCC diagnostic ignored "-Wsign-compare"
int main()
{
static_assert(sizeof(int) == 4); // precondition
// Quite surprisingly
static_assert(-1 > 1U); //< warning: sign-unsign comparison
// because after implicit conversion of -1 to the RHS type (`unsigned int`)
// the expression is equivalent to:
static_assert(0xFFFFFFFFU > 1U);
static_assert(0xFFFFFFFFU == static_cast<unsigned>(-1));
// In contrast, the cmp_* family compares integers as most expected -
// negative signed integers always compare less than unsigned integers:
static_assert(std::cmp_less(-1, 1U));
static_assert(std::cmp_less_equal(-1, 1U));
static_assert(!std::cmp_greater(-1, 1U));
static_assert(!std::cmp_greater_equal(-1, 1U));
static_assert(-1 == 0xFFFFFFFFU); //< warning: sign-unsign comparison
static_assert(std::cmp_not_equal(-1, 0xFFFFFFFFU));
}
like... -1 > 1U being true is the jump scare of the century and I will not be recovering π
π See also π
equal_toβ function object implementingx == y(class template)not_equal_toβ function object implementingx != y(class template)lessβ function object implementingx < y(class template)greaterβ function object implementingx > y(class template)less_equalβ function object implementingx <= y(class template)greater_equalβ function object implementingx >= y(class template)ranges::equal_to(C++20)β constrained function object implementingx == y(class)ranges::not_equal_to(C++20)β constrained function object implementingx != y(class)ranges::less(C++20)β constrained function object implementingx < y(class)ranges::greater(C++20)β constrained function object implementingx > y(class)ranges::less_equal(C++20)β constrained function object implementingx <= y(class)ranges::greater_equal(C++20)β constrained function object implementingx >= y(class)compare_three_way(C++20)β constrained function object implementingx <=> y(class)in_range(C++20)β checks if an integer value is in the range of a given integer type (function template)numeric_limitsβ provides an interface to query properties of all fundamental numeric types (class template)
that's the whole page, bestie. go forth and compare integers without fear. π β¨
π sign-off time: this lil masterpiece lives athttp://cppreference.com, is dated2024.06.10, and its manpage tag isstd::cmp_eq...eater_equal(3)(yes, the header got aggressively truncated by the terminal and honestly, we respect the drama). ily, bye π«ΆπΈ
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms