I have an object of type std::variant<std::monostate, T...>
, but I need to call a function that only accepts std::variant<T...>
.
Is there a way I could convert a std::variant<std::monostate, T...>
to std::variant<T...>
if I'm sure it isn't a std::monostate
?
I have an object of type std::variant<std::monostate, T...>
, but I need to call a function that only accepts std::variant<T...>
.
Is there a way I could convert a std::variant<std::monostate, T...>
to std::variant<T...>
if I'm sure it isn't a std::monostate
?
1 Answer
Reset to default 5You can use std::visit()
, you just need to handle the case where it is std::monostate
, you can throw an exception for now, or in C++23 use std::unreachable
:
std::variant<std::monostate, std::string, int> monostate_variant = 2;
std::variant<std::string, int> variant2 = std::visit(
overloads{
[](std::monostate) ->std::variant<std::string, int>
{ throw std::runtime_error("actually a monostate"); },
[](auto&& obj) -> std::variant<std::string, int>
{ return std::move(obj);}
},
std::move(monostate_variant)
);
The implementation of overloads
is from the std::visit()
cppreference page.
For the simple case that std::monostate
is the first parameter, you can use this template:
template <typename...Ts>
auto remove_monostate(std::variant<std::monostate, Ts...> var)
{
return std::visit(
overloads{
[](std::monostate) ->std::variant<Ts...>
{ throw std::runtime_error("actually a monostate"); },
[](auto&& obj) -> std::variant<Ts...>
{ return std::move(obj);}
},
std::move(var)
);
}
auto variant_without_monostate = remove_monostate(std::move(monostate_variant));
Online Demo
And, if their types are not in the same order, then you can modify the template and pass in the needed variant type as a template parameter, and use it as a return type for the lambdas.
C++20 perfect forwarding version (1 less move)
template <typename...Ts>
auto remove_monostate_helper(std::variant<std::monostate, Ts...>) -> std::variant<Ts...>;
template <typename T>
auto remove_monostate(T&& var)
{
using return_type = decltype(remove_monostate_helper(var));
return std::visit(
overloads{
[](std::monostate) -> return_type
{ throw std::runtime_error("actually a monostate"); },
[]<typename U>(U&& obj) -> return_type
{ return std::forward<U>(obj);}
},
std::forward<T>(var)
);
}