为什么我要通过std :: variant获得std :: bad_variant_access?

问题描述 投票:1回答:2

考虑:

#include <variant>
#include <iostream>

int main()
{
    double foo = 666.666;
    std::variant<double, uint64_t> v = foo;
    std::cout << std::get<uint64_t>(v) << std::endl;
    return 0;
}

这导致:

terminate called after throwing an instance of 'std::bad_variant_access'
  what():  Unexpected index
Aborted (core dumped)

为什么?

我已经了解到std::variant将替代union。但是,如果这种基本的东西失败了,那有什么用呢?

c++ c++17 ubuntu-18.04 variant gcc7
2个回答
5
投票

我知道std :: variant将替代union。

是。有点儿。但是您的误解似乎与C ++中的联合有关。从cppreference

从最近未写的工会成员那里读来的行为是不确定的。作为非标准语言扩展,许多编译器都实现了读取联合中不活动成员的功能。

请注意,这与C不同,这是常见的误解的根本原因,该误解是在C ++中也允许访问非活动成员。

为什么?

因为std::variant模仿联合但增加了一些安全性,并且std::get是...

基于索引的值访问器:如果v.index()== I,则返回对v中存储的值的引用。否则,抛出std :: bad_variant_access。如果我不是,则调用格式错误变体中的有效索引。

但是,如果这种基本的东西失败了,那有什么用呢?

C ++中的联盟绝不会那样使用。如果要将两个或多个值压缩到同一内存中,则并集可以节省内存(但在任何时候都只能使用其中一个)。我从来没有遇到过真正的用例。但是std::get是C ++类型的不错补充。更大的图景是很长一段时间以来已经存在所谓的产品类型,例如std::variant,从某种意义上来说,它们可以表示的值集为std::pair<T1,T2>。现在有了T1 x T2(和std::variant),C ++也具有适当的(=从某种程度上从未从并集获得类型安全性)和类型,即std::any可以表示的一组值是std::variant<T1,T2>(对不起使用草率的表示法,希望很清楚)。


1
投票

T1 + T2是一个“类型安全的联合”,这意味着它将检查您从中得到的是最后存储在其中的类型。在此示例中,您存储的是std::variant,但尝试获取double

请在此处查看文档:uint64_t

基于类型的值访问器:如果v持有替代T,则返回对v中存储的值的引用。否则,抛出std :: bad_variant_access。如果T不是Types的唯一元素,则呼叫格式不正确。

© www.soinside.com 2019 - 2024. All rights reserved.