首页 > 其他分享 >泛形variant+visit

泛形variant+visit

时间:2024-03-29 14:01:49浏览次数:20  
标签:std cout visit variant 泛形 类型 include

泛形variant+visit

1.引言

python里可以让一个变量变成不同的类型,拥有不同的值,且根据不同的类型执行不同的操作,当不同的类型拥有同样的函数时,这样我们就不用再重复写一堆代码了

但如果在c++中实现类似的功能,比较经典的处理方式是用虚函数 + 子类重写的方式,

class Base{
    virtual void accept(visitor) = 0;
}
class sub1:Base{
    void accept(visitor){
    visitor->visit(this)
}
}
class sub2:Base{
void accept(visitor){
    visitor->visit(this)
}

这样的话代码的冗余度就高了,且每次添加新都需要新建一个类

有没有更简单一些的方式呢,接下来的variant+visit能够很好的解决该问题

2. variant

std::variant 是 C++17 标准中引入的一种数据类型,它允许在一个变量中存储多种不同类型的值,这些值被称为“备选项”或“可替代项”。std::variant 本质上是一种类型安全的联合(Union)类型

2.1 特点

  1. 类型安全std::variant 确保在编译时检查类型,因此可以避免运行时的类型错误。
  2. 多态值std::variant 可以存储不同的数据类型,这使得它非常灵活,可以在一种类型安全的情况下处理多态值。
  3. 访问备选项:使用 std::get<>()std::get_if<>() 可以访问 std::variant 中存储的备选项。此外,std::visit() 函数提供了一种通用的方式来访问 std::variant 中的值,类似于多态行为。
  4. 异常安全:与使用裸指针和类型转换相比,std::variant 提供了更好的异常安全性,因为它保证只能存储其所允许的类型。
  5. 替代方案:在以前的 C++ 版本中,通常会使用联合(Union)类型来实现多态值的存储,但这种方法没有提供类型安全性,并且通常需要显式的类型检查和转换。std::variant 提供了一个更安全、更方便的替代方案。

2.2 简单示例

#include <iostream>
#include <variant>
#include <string>

int main() {
    std::variant<int, double, std::string> v;
    v = 10;
    std::cout << "Value: " << std::get<int>(v) << std::endl;

    v = 3.14;
    std::cout << "Value: " << std::get<double>(v) << std::endl;

    v = "Hello, variant!";
    std::cout << "Value: " << std::get<std::string>(v) << std::endl;

    return 0;
}

如果只是简单的使用variant, 从上例可以看出,每次都要往std::get<>里传入确定的类型,这样的话,只是实现的一个带有类型擦除的不同类型的存储结构,无法根据类型做不同的执行

3. variant+visit

std::visit 用于访问 std::variant 中存储的值。使用方式如下

3.1 示例1——多类型同名函数调用

#include <iostream>
#include <string>
#include <variant>
#include <vector>
 
// variant
using var_t = std::variant<int, long, double, std::string>;

int main() {
    std::string s = "\n";
    std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
    for(auto&& v: vec) {
        std::visit([&](auto&& arg){
            std::cout << arg; 
            std::cout << s;
        }, v);
    }
}
  • output
10
15
1.5
hello

3.2 示例2——返回值

#include <iostream>
#include <string>
#include <variant>
#include <vector>
 
// variant
using var_t = std::variant<int, long, double, std::string>;

int main() {
    std::string s = "\n";
    std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
    for(auto&& v: vec) {
        //返回w的值为不同的值相加
     var_t w = std::visit([](auto&& arg) -> var_t {return arg + arg;}, v);
    }
}

3.3 示例3——类型匹配1

  • 类型匹配 即可根据不同的类型做不同的执行
#include <iostream>
#include <variant>
#include <string>
struct PrintVisitor {
    void operator()(int value) const {
        std::cout << "Integer value: " << value << std::endl;
    }
    void operator()(double value) const {
        std::cout << "Double value: " << value << std::endl;
    }
    void operator()(const std::string& value) const {
        std::cout << "String value: " << value << std::endl;
    }
};

int main() {
    std::variant<int, double, std::string> v;
    v = 10;
    std::visit(PrintVisitor{}, v);
    v = 3.14;
    std::visit(PrintVisitor{}, v);
    v = "Hello, variant!";
    std::visit(PrintVisitor{}, v);

    return 0;
}

3.4 示例4——类型匹配2

#include <iomanip>
#include <iostream>
#include <string>
#include <variant>
#include <vector>
 
// 要观览的 variant
using var_t = std::variant<int, long, double, std::string>;
 
// 1 的辅助常量
template<class> inline constexpr bool always_false_v = false;
 
// 2 的辅助类型
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
// 显式推导指引( C++20 起不需要)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
 
int main() {
    std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
    for(auto&& v: vec) {
        // 1 类型匹配观览器:亦能为带 4 个重载的 operator() 的类
        std::visit([](auto&& arg) {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string with value " << std::quoted(arg) << '\n';
            else 
                static_assert(always_false_v<T>, "non-exhaustive visitor!");
        }, v);
    }
 
    for (auto&& v: vec) {
        // 2类型匹配观览器:有三个重载的 operator() 的类
        std::visit(overloaded {
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
        }, v);
    }
}
  • output
int with value 10
long with value 15
double with value 1.5
std::string with value "hello"
10 15 1.500000 "hello" 

4. 结语

使用varirant+visit 能够避免多态使用里的不必要新类够建,与lambda结合能快速实现简洁且通用的代码,是一块功能强大的语法糖

本文由博客一文多发平台 OpenWrite 发布!

标签:std,cout,visit,variant,泛形,类型,include
From: https://www.cnblogs.com/InsiApple/p/18103716

相关文章

  • 【Qt5】QVariant
    2024年3月22日,周五下午什么是QVariantQVariant是Qt框架中用于处理各种数据类型的通用类。它可以存储几乎任何类型的数据,并且能够在不同的Qt类之间进行类型转换。QVariant在Qt中被广泛用于处理不同的数据类型,包括基本数据类型(如整数、浮点数、布尔值等)、字符串、自定......
  • Shopify 商品售卖属性优化插件之G:Variant Image + Color Swatch
    推荐一款很赞的Shopify商品售卖属性呈现样式优化的APP(G:VariantImage+ColorSwatch)安装此类插件列表页效果对比 图片来源:shejolly.com安装此类插件详情页效果对比未安装插件效果,图片来源:shejolly.com已安装插件效果,图片来源:shejolly.com未......
  • Revisiting Heterophily For Graph Neural Networks
    目录概符号说明HomophilymetricsPost-aggregationnodesimilaritymatrix代码LuanS.,HuaC.,LuQ.,ZhuJ.,ZhaoM.,ZhangS.,ChangX.andPrecupD.Revisitingheterophilyforgraphneuralnetworks.NIPS,2022.概介绍了一种新的graphhomophilymetrics.符......
  • 协变返回类型(covariant return type)
    协变返回类型(covariantreturntype)C++中的协变返回类型(covariantreturntype)是指派生类(子类)中的虚函数返回类型可以是基类(父类)中虚函数返回类型的子类。这个特性使得在派生类中可以返回更具体的类型,而不违反了虚函数的约定。在C++11中,如果派生类的虚函数覆盖基类的虚函数,并......
  • [Typescript 5] Intro to Variants (keyword in & out)
    Covariance-producer-out-functionreturnposition-samearrowdirectionContravariance-packager-in-functionparamposition-differentarrowdirectionInvariance-bothproducerandpackager-oneinfunctionreturnpositionandanotherinfun......
  • 【题解】CF185D - Visit of the Great
    【题解】CF185D-VisitoftheGreat设\(d=\gcd(k^{2^a}+1,k^{2^b}+1),(a<b)\),则:\[k^{2^a}\equivk^{2^b}\equiv-1(\bmodd)\]所以\[1\equiv(-1)^{2^{b-a}}\equivk^{2^a*2^{b-a}}\equivk^{2^b}\equiv1(\bmodd)\]所以\(d\)为\(1\)或\(2\)。设\(t......
  • 访问模式(visitor)
    1#include<iostream>2#include<string>3usingnamespacestd;45//访问者模式:核心叫做双重分发:两个多态:accept,visit67classXiaoMi;8classHuaWei;9classOppo;10classCellPhoneVisitor{11public:12virtualvoidvisit(Xia......
  • 【代码复现(吐槽向)】Revisiting a Methodology for Efficient CNN Architectures in Pr
    【论文写不出来,痛苦中】这篇文章是我看到框架最简单,效果最好的对于公开数据集的攻击没有之一。代码:KULeuven-COSIC/TCHES20V3_CNN_SCA(github.com)吐槽:1坑:TF的版本问题,有了torch,谁用TF,但是偏偏GITHUB上所有的SCA的代码都是TF写的,还有丧心病狂TF1.x,版本安装几十年,不如选一个服......
  • Only the invariant culture is supported in globalization-invariant mode
     错误信息:全球化不变模式只支持不变文化。看见https://aka.ms/GlobalizationInvariantMode了解更多信息修改引用配置即可:<InvariantGlobalization>true</InvariantGlobalization>改为false Onlytheinvariantcultureissupportedinglobalization-invariantmode.See......
  • delphi 变体Variant数组常用操作
    变体Variant数组常用操作代码procedureTForm1.Button1Click(Sender:TObject);varArr1,Arr2,Arr3:Variant;I,J:Integer;begin//创建包含10个整数类型元素的变体数组Arr1:=VarArrayCreate([0,9],varInteger);//创建2维数组,其中第1维是3个元素,第2维是5......