std::variant
provides the following access functions:
std::get_if
: take pointer to variant
, return pointer to alternative.
template <std::size_t I, typename... Ts>
auto* std::get_if(std::variant<Ts...>* pv) noexcept;
If
pv
is not a null pointer andpv->index() == I
, returns a pointer to the value stored in the variant pointed to bypv
. Otherwise, returns a null pointer value.
This means that get_if
's implementation roughly looks like this:
template <std::size_t I, typename... Ts>
auto* std::get_if(std::variant<Ts...>* pv) noexcept
{
if(pv == nullptr) return nullptr;
if(pv->index() != I) return nullptr;
return &(pv->real_get<I>());
}
std::get
: take reference to variant
, return reference to alternative, throw
on invalid access.
template <std::size_t I, typename... Ts>
auto& std::get(std::variant<Ts...>& v);
If
v.index() == I
, returns a reference to the value stored inv
. Otherwise, throwsstd::bad_variant_access
.
This means that get
's implementation roughly looks like this:
template <std::size_t I, typename... Ts>
auto& std::get(std::variant<Ts...>& v)
{
if(v.index() != I) throw std::bad_variant_access{};
return v.real_get<I>();
}
I want an unsafe access function that:
Is noexcept
.
Takes a reference to a variant
, avoiding any pv == nullptr
check.
Has undefined behavior if v.index() != I
.
Why? Because there may be some situations where I am 100% sure that a particular variant
instance contains a specific type in a code path. Also, it would be useful when writing generic code that already separately checked v.index() != I
(e.g. writing my own visit
).
Example implementation:
template <std::size_t I, typename... Ts>
auto& unsafe_get(std::variant<Ts...>& v)
{
return v.real_get<I>();
}
Is there something like this in the standard? I couldn't find it. If not, is this possible to implement for std::variant
, or do I need to roll out my own variant
implementation?
As pointed out by @T.C. in the comments, your first and third desiderata are mutually incompatible. This was spelled out in N3279, titled "Conservative use of noexcept in the Library".
There are essentially two classes of contracts: narrow and wide. A wide contract for a function or operation does not specify any undefined behavior.
Such a contract has no preconditions. Only functions with wide contracts are marked noexcept
in the Standard Library.
OTOH, a narrow contract is a contract which is not wide. Narrow contracts for a functions or operations result in undefined behavior when called in a manner that violates the documented contract. They cannot be marked noexcept
. Instead, the best you can expect is that they are documented as "Throws: Nothing."
It appears that you are out of luck and no such unchecked access is provided in the current proposals for std::variant
.