我有可以简化为的代码
std::variant<float, int> v[2] = foo();
int a = std::get<decltype(a)>(v[0]);
float b = std::get<decltype(b)>(v[1]);
显然,如果
foo()
返回错误的变体,这可能会抛出异常,但这不是我的问题。 (真正的代码有一个catch
)。我的问题是 decltype(a)
违反了“不要重复自己”原则。
是否有一种更简洁的方法来初始化 a 和 b,并且如果类型与期望不符,仍然抛出异常?特别是,当我尝试初始化 static_cast<int>(std::get<float>(v))
时,如果变体包含浮点数,我
不想要
int
。
您可以将对
get
的调用包装在隐式转换为目标类型的模板中。
template<typename... Ts>
struct variant_unwrapper {
std::variant<Ts...> & var;
template <typename T>
operator T() { return std::get<T>(var); }
};
template<typename... Ts>
variant_unwrapper(std::variant<Ts...> &) -> variant_unwrapper<Ts...>;
如果你的目标是C++20,则不需要推导指南
IMO 允许模板推导接管会很好,因此提供辅助函数应该可以完成这项工作:
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);
正如 @paulo 在评论中所说的那样,似乎 DRY 解决方案是使用
auto
进行声明,更改:
int a = std::get<decltype(a)>(v[0]);
至:
auto a = std::get<int>(v[0]);
您只需为类型 (
int
) 和变量 (a
) 各命名一次。如果将声明和初始化分开,则不起作用,因此您仍然需要:
int a;
...
a = std::get<decltype(a)>(v[0]);
在这种情况下,但如果您编写所有 C++ 代码,将声明推迟到定义点,则通常不需要这样做。