c++ - 为什么我无法检索变体的索引并使用它来获取其内容?

标签 c++ c++17 variant

我正在尝试访问变体的内容。我不知道里面有什么,但幸运的是,该变体知道。所以我想我只需询问变体它所在的索引,然后使用该索引来 std::get 其内容。

但这不能编译:

#include <variant>

int main()
{
  std::variant<int, float, char> var { 42.0F };

  const std::size_t idx = var.index();

  auto res = std::get<idx>(var);

  return 0;
}

错误发生在std::get调用中:

error: no matching function for call to ‘get<idx>(std::variant<int, float, char>&)’
   auto res = std::get<idx>(var);
                               ^
In file included from /usr/include/c++/8/variant:37,
                 from main.cpp:1:
/usr/include/c++/8/utility:216:5: note: candidate: ‘template<long unsigned int _Int, class _Tp1, class _Tp2> constexpr typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(std::pair<_Tp1, _Tp2>&)’
     get(std::pair<_Tp1, _Tp2>& __in) noexcept
     ^~~
/usr/include/c++/8/utility:216:5: note:   template argument deduction/substitution failed:
main.cpp:9:31: error: the value of ‘idx’ is not usable in a constant expression
   auto res = std::get<idx>(var);
                               ^
main.cpp:7:15: note: ‘std::size_t idx’ is not const
   std::size_t idx = var.index();
               ^~~

我该如何解决这个问题?

最佳答案

编译器需要知道 idx 的值在编译时 std::get<idx>()工作,因为它被用作模板参数。

第一个选项:如果代码要在编译时运行,则将所有内容设置为 constexpr :

constexpr std::variant<int, float, char> var { 42.0f };

constexpr std::size_t idx = var.index();

constexpr auto res = std::get<idx>(var);

这有效是因为 std::variantconstexpr友好(其构造函数和方法都是 constexpr )。

第二个选项:如果代码不打算在编译时运行(很可能是这种情况),则编译器无法在编译时推断 res 的类型,因为它可能是三个不同的东西( intfloatchar )。 C++是静态类型语言,编译器必须能够推导出 auto res = ... 的类型来自后面的表达式(即它必须始终是相同的类型)。

您可以使用std::get<T> ,使用类型而不是索引,如果您已经知道它将是什么:

std::variant<int, float, char> var { 42.0f }; // chooses float

auto res = std::get<float>(var);

一般情况下,使用std::holds_alternative检查变体是否持有每种给定类型,并分别处理它们:

std::variant<int, float, char> var { 42.0f };

if (std::holds_alternative<int>(var)) {
    auto int_res = std::get<int>(var); // int&
    // ...
} else if (std::holds_alternative<float>(var)) {
    auto float_res = std::get<float>(var); // float&
    // ...
} else {
    auto char_res = std::get<char>(var); // char&
    // ...
}

或者您可以使用std::visit 。这稍微复杂一些:您可以使用与类型无关并且适用于所有变体类型的 lambda/模板函数,或者传递带有重载调用运算符的仿函数:

std::variant<int, float, char> var { 42.0f };

std::size_t idx = var.index();

std::visit([](auto&& val) {
    // use val, which may be int&, float& or char&
}, var);

参见std::visit了解详细信息和示例。

关于c++ - 为什么我无法检索变体的索引并使用它来获取其内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59103484/

相关文章:

c++ - 负责从sqlite3_column_text中释放指针的sqlite c/c++ api

c++ - std::reduce 似乎将结果转换为整数

c++ - 从函数返回值

C++:std::variant 可以容纳 vector 、 map 和其他容器吗?

c++ - std::map:返回由具有相等值的键组成的 vector

c++ - 模板特化歧义 : either specialized or original method may be linked

c++ - 置换 vector

c++ - 为什么 std::abs(9484282305798401ull) = 9484282305798400?

list - 如何处理多态变体列表?

delphi - 当天结束时的变体误传