The current API for std::variant
has no unchecked version of std::get
. I don't know why it was standardized that way; anything I say would just be guessing.
However, you can get close to the desired behavior by writing *std::get_if<T>(&variant)
. If variant
doesn't hold T
at that time, std::get_if<T>
returns nullptr
, so dereferencing it is undefined behavior. The compiler can thus assume that the variant holds T
.
In practice, this isn't the easiest optimization for the compiler to do. Compared to a simple tagged union, the code it emits may not be as good. The following code:
int const& get_int(std::variant<int, std::string> const& variant)
{
return *std::get_if<int>(&variant);
}
Emits this with clang 5.0.0:
get_int(std::variant<int, std::string> const&):
xor eax, eax
cmp dword ptr [rdi + 24], 0
cmove rax, rdi
ret
It is comparing the variant's index and conditionally moving the return value when the index is correct. Even though it would be UB for the index to be incorrect, clang is currently unable to optimize the comparison away.
Interestingly, returning an int
instead of a reference optimizes the check away:
int get_int(std::variant<int, std::string> const& variant)
{
return *std::get_if<int>(&variant);
}
Emits:
get_int(std::variant<int, std::string> const&):
mov eax, dword ptr [rdi]
ret
You could help the compiler by using __builtin_unreachable()
or __assume
, but gcc is currently the only compiler capable of removing the checks when you do so.
std::variant
is for: 'a type-safe union'. If you don't want it type-safe, or want UB, don't use it: use aunion
. – Chandigarhstd::variant
might not have astd::unchecked_get
. I don't know if that's really what was discussed in the standards meetings, but there is logic behind the reasoning – Tipper