Since the std::variant
is not allowed to compare with one of its alternative types in the standard library, I am implementing the compare function using C++20 <=>
operator:
template <typename... Args, typename T>
constexpr auto operator<=>(const std::variant<Args...>& v, const T& t) {
return std::visit([&t](const auto& u) -> std::partial_ordering {
if constexpr (requires { u <=> t; }) return u <=> t;
else return std::partial_ordering::unordered;
}, v);
}
But when I testing the above function with my own defined std::variant
:
using Variant = std::variant<double, int, std::string_view>;
constexpr Variant v1{1.0};
constexpr Variant v2{1};
constexpr Variant v3{"hello"};
static_assert(v1 < 2);
// compile error
static_assert(v2 < 2);
static_assert(!(v3 > 2) && !(v3 < 2) && !std::is_eq(v3 <=> 2));
The second assertion couldn't compile, GCC says:
<source>:19:17: error: non-constant condition for static assertion
19 | static_assert(v2 < 2);
| ^~~~~~~~~
<source>:19:24: in 'constexpr' expansion of 'operator<=><double, int, std::basic_string_view<char, std::char_traits<char> >, int>(v2, 2)'
<source>:19:17: error: '<anonymous>' is not a constant expression
Why is v2 < 2
not a constant expression? or it's just a GCC bug? Weirder, when I change the second assertion to compare with double
, this can compile:
static_assert(v2 < 2.0);
Update:
Clang can pass three assertions, but MSVC can only pass the third assertion, it seems MSVC also has a bug.
The class template std::variant represents a type-safe union. An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value (this state is hard to achieve, see valueless_by_exception).
Since this function is specific to a given type, you don't need RTTI to perform the operations required by std::any .
According to cppreference ::std::variant must not allocate dynamic memory. As with unions, if a variant holds a value of some object type T, the object representation of T is allocated directly within the object representation of the variant itself. Variant is not allowed to allocate additional (dynamic) memory.
It holds one of several alternatives in a type-safe way. No extra memory allocation is needed. The variant needs the size of the max of the sizes of the alternatives, plus some little extra space for knowing the currently active value. By default, it initializes with the default value of the first alternative.
The first example reduces to:
#include <compare>
// this one is okay
static_assert(std::partial_ordering(std::strong_ordering::less) < 0);
// this one fails with non-constant condition
static_assert(std::partial_ordering(1 <=> 2) < 0);
Everything here is obviously a constant expression. The fact that strong_ordering::less
can be converted to partial_ordering::less
just fine while 1 <=> 2
can't be (on gcc) suggests that this is a bug in the compiler, rather than the library.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With