Date: Sat, 23 Nov 2024 07:34:24 +0100
On 22/11/2024 22.48, Vladimir Grigoriev via Std-Discussion wrote:
> Could standard functions cmp_equal, cmp_not_equal, cmp_less,
> cmp_greater, cmp_less_equal, cmp_greater_equal be overloaded for
> enumerations?
> Something like for example
> template <typename T, typename U>
> requires std::is_enum_v<T> && std::is_same_v<T, U>
> constexpr bool cmp_less( T t, U u ) noexcept
> {
> return std::to_underlying( t ) < std::to_underlying( u );
> }
enums are not always to be treated like integral values, similarly to
character types and bool, which is why the paper did not propose to add
those overloads, and recommends against it
See https://wg21.link/p0586#Design, and the note at the end
> [Note: These function templates cannot be used to compare byte,
char, char8_t, char32_t, wchar_t, and bool. --end note]
I see mainly two issues, the first one is that you loos type safety:
enum class e : int {v = 0};
e::v < 1; // does not compile, as intended
cmp_less(e::v,1); // should behave consistently
If you really want to compare enums of the same type, I would claim that
a different name should be preferred, as the selling point of cmp_* is
to compare *numerical* entities of *different* types.
But why not define the comparison operator for your enums and let the do
the right thing instead of using a named function?
Second in some cases the behavior is not consistent between environment,
making it useless.
This happens if an underlying is not specified, or is for example
specified as char.
enum class e : char { v = 'a'};
cmp_less(e::v,e{-1}); // might be true or false
TL;DR if you do define your own numerical type (enum or not), you do not
to use the cmp_* functions. You can define your comparison operators to
work as if you where using cmp_*, if this is what you want.
Federico
> Could standard functions cmp_equal, cmp_not_equal, cmp_less,
> cmp_greater, cmp_less_equal, cmp_greater_equal be overloaded for
> enumerations?
> Something like for example
> template <typename T, typename U>
> requires std::is_enum_v<T> && std::is_same_v<T, U>
> constexpr bool cmp_less( T t, U u ) noexcept
> {
> return std::to_underlying( t ) < std::to_underlying( u );
> }
enums are not always to be treated like integral values, similarly to
character types and bool, which is why the paper did not propose to add
those overloads, and recommends against it
See https://wg21.link/p0586#Design, and the note at the end
> [Note: These function templates cannot be used to compare byte,
char, char8_t, char32_t, wchar_t, and bool. --end note]
I see mainly two issues, the first one is that you loos type safety:
enum class e : int {v = 0};
e::v < 1; // does not compile, as intended
cmp_less(e::v,1); // should behave consistently
If you really want to compare enums of the same type, I would claim that
a different name should be preferred, as the selling point of cmp_* is
to compare *numerical* entities of *different* types.
But why not define the comparison operator for your enums and let the do
the right thing instead of using a named function?
Second in some cases the behavior is not consistent between environment,
making it useless.
This happens if an underlying is not specified, or is for example
specified as char.
enum class e : char { v = 'a'};
cmp_less(e::v,e{-1}); // might be true or false
TL;DR if you do define your own numerical type (enum or not), you do not
to use the cmp_* functions. You can define your comparison operators to
work as if you where using cmp_*, if this is what you want.
Federico
Received on 2024-11-23 06:34:32