[C++]std::variant

Koarz
2023-07-15 / 0 评论 / 0 阅读 / 正在检测是否收录...

std::variant介绍


类模板 std::variant 表示一个类型安全的联合体。 std::variant 的一个实例在任意时刻要么保有其一个可选类型之一的值,要么在错误情况下无值(此状态难以达成,见 valueless_by_exception )。

与联合体在聚合初始化中的行为一致, 若 variant 保有某个对象类型 T 的值,则直接于 variant 的对象表示中分配 T 的对象表示。不允许 variant 分配额外的(动态)内存。

variant 不容许保有引用、数组,或类型 void 。空 variant 亦为病式(可用 std::variant<std::monostate> 代替)。

variant 容许保有同一类型多于一次,而且可保有同一类型的不同 cv 限定版本。

同联合体,默认构造的 variant 保有其首个选项的值,除非该选项不是可默认构造的(该情况下 variant 亦非可默认构造:能用辅助类 std::monostate 使这种 variant 可默认构造)。

std::variant的简单使用
#include <iostream>
#include <variant>
using var_T = std::variant<int,double,char>;
int main() {
    var_T v;
    v = 1;//给v复制int
    std::cout << std::get<int>(v) << ' ' << v.index() << '\n';
    v = 2.5;//给v赋值double
    std::cout << std::get<double>(v) << ' ' << v.index() << '\n';
    v = 'A';//给v赋值char
    std::cout << std::get<char>(v) << ' ' << v.index() << '\n';
    v = "Hello cremache!" //error,v不能储存字符串类型
    return 0;
}

输出:

1 0
2.5 1
A 2

分析:
示例给的 variant 可以储存int,double,char类型的数据,如果我们需要将v储存的值输出,那么就需要用到std::get<type>(var),但是这种输出需要你显式指出v储存的值的类型,auto 在这里是不能使用的,当然除了具体的数据类型,你也可以使用 0 代表 int ,1 代表 double ,2 代表 char(具体请根据你自己的定义,这里的012是根据我的定义)。
除了std::get() C++还提供了std::get_if() ,get_if 同样需要显式指出数据类型,get_if的参数是指向 variant 的指针,返回值是指向存储于被指向的 variant 中值的指针,错误时为空指针。
index()可以返回 variant 当前所保有的可选项的零基下标。
若 variant 因异常无值( valueless_by_exception ),则返回 variant_npos 。
通俗来说就是0是int,1是double(仅限示例)。

在std::vector中使用std::variant
#include <iostream>
#include <variant>
#include <vector>
using var_T = std::variant<int,double,char>;
template<class... Ts> struct overloaded : Ts... {using Ts::operator()...;};
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main() {
    std::vector<var_T> n{ 2.5 , 'A', 1};
    for(auto v : n)
    {
        std::visit(overloaded{
                [](int arg) { std::cout << arg; },
                [](double arg) {std::cout << std::fixed << arg;},
                [](char arg) {std::cout << arg;},
        },v);
        std::cout << '\n';
    }
    return 0;
}

输出:

2.50000
A
1

这是cppreference给出的写法,我们需要使用visit()函数来访问数据,但是这种写法非常麻烦,这里有一个难懂的overloaded 在 Stack Overflow 中有大佬对overloaded做出解释:


但是这种写法我们可以简化!

#include <iostream>
#include <variant>
#include <vector>
using var_T = std::variant<int,double,char>;
int main() {
    std::vector<var_T> n{ 2.5 , 'A', 1};
    for(auto v : n)
    {
        std::visit([](auto arg){std::cout << arg;},v);
        std::cout << '\n';
    }
    return 0;
}

直接使用使用auto推导类型,就不用我们分情况写了。当然,具体操作还是得根据具体情况使用。

0

评论 (0)

取消