指定从 std::variant 获取类型的更简洁方法?

MSa*_*ers 4 c++ c++17 std-variant

我有可以简化为的代码

std::variant<float, int> v[2] = foo();
int a = std::get<decltype(a)>(v[0]);
float b = std::get<decltype(b)>(v[1]);
Run Code Online (Sandbox Code Playgroud)

显然,如果返回错误的变体,这可能会抛出foo()异常,但这不是我的问题。(真正的代码有一个catch)。我的问题是这decltype(a)违反了“不要重复自己”原则。

是否有一种更简洁的方法来初始化 a 和 b,并且如果类型与预期不匹配,仍然会抛出异常?特别是,static_cast<int>(std::get<float>(v))尝试初始化int.

Cal*_*eth 12

您可以将调用包装get在隐式转换为目标类型的模板中。

template<typename... Ts>
struct variant_unwrapper {
    std::variant<Ts...> & var;
    template <typename T>
    operator T() { return std::get<T>(var); }
};
Run Code Online (Sandbox Code Playgroud)

在 coliru 上查看

  • @PaulSanders - 你实际上并没有用“short”初始化“v[2]”。该片段中没有实际问题。 (3认同)
  • @PaulSanders https://coliru.stacked-crooked.com/a/f54c84077ae8fa73 (2认同)

Mar*_*k R 10

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);
Run Code Online (Sandbox Code Playgroud)


Sha*_*ger 5

正如@paulo 在评论中所说,似乎 DRY 解决方案是用于auto声明,更改:

int a = std::get<decltype(a)>(v[0]);
Run Code Online (Sandbox Code Playgroud)

到:

auto a = std::get<int>(v[0]);
Run Code Online (Sandbox Code Playgroud)

您只需为类型 ( int) 和变量 ( a) 各命名一次。如果将声明和初始化分开,则不起作用,因此您仍然需要:

int a;
...
a = std::get<decltype(a)>(v[0]);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,但如果您编写的所有 C++ 代码都将声明推迟到定义点,则通常不需要这样做。