I've got code that can be simplified to
std::variant<float, int> v[2] = foo();
int a = std::get<decltype(a)>(v[0]);
float b = std::get<decltype(b)>(v[1]);
Obviously this can go throw if foo()
returns the wrong variants, but that's not my problem here. (The real code has a catch
). My problem is that the decltype(a)
violates the Don't Repeat Yourself principle.
Is there a cleaner way to initialize a and b, and still throw if the types do not match expectations? In particular, I don't want a static_cast<int>(std::get<float>(v))
if the variant contains a float while I'm trying to initialize an int
.
CodePudding user response:
You could wrap your call to get
in a template that implicitly converts to the target type.
template<typename... Ts>
struct variant_unwrapper {
std::variant<Ts...> & var;
template <typename T>
operator T() { return std::get<T>(var); }
};
CodePudding user response:
IMO it would be nice to allow template deduction to take over, so providing a helper function should do the job:
template<typename T, typename...VariantParams>
void get_from(const std::variant<VariantParams...>& v, T& value)
{
value = ::std::get<T>(v);
}
int a;
get_from(v[0], a);
CodePudding user response:
As @paulo says in the comments, seems like the DRY solution is to use auto
for the declaration, changing:
int a = std::get<decltype(a)>(v[0]);
to:
auto a = std::get<int>(v[0]);
You only name the type (int
) and the variable (a
) once each. Doesn't work if you separate declaration and initialization, so you'd still need:
int a;
...
a = std::get<decltype(a)>(v[0]);
in that case, but if you write all your C code deferring declarations until the point of definition, it's not needed often.