当前位置:首页 > 工具 > 正文内容

探索C++17的variant类型及其应用

访客 工具 2026年7月13日 4

variant类型解析

variant是C++17标准库引入的一种多值容器类型。variant<A, B, C>可以存储A、B或C类型的数据。

  • 与传统C语言union类似,variant也是一种联合类型,能够容纳多种数据类型,但在任意时刻只能保存其中一种类型的数据。
  • 与传统union不同的是,variant是一种类型安全的联合类型,能够自行识别当前存储的数据类型,无需外部辅助。

例如,var = variant<int, float, std::string>表示var是一个可以存储整数、浮点数或字符串的对象。

  • var.index()返回当前存储数据类型的索引位置,第一个类型索引为0,第二个为1,依此类推。
  • std::holds_alternative<T>(var)检查variant是否存储了类型T的数据。
  • std::get<I>(var)当variant存储的数据类型索引为I时返回该数据,否则抛出异常。
  • std::get_if<I>(&var)当variant存储的数据类型索引为I时返回指向该数据的指针,否则返回nullptr。
  • std::get<T>(var)当variant存储的数据类型为T时返回该数据,否则抛出异常。
  • std::get_if<T>(&var)当variant存储的数据类型为T时返回指向该数据的指针,否则返回nullptr。
#include <iostream>
#include <string>
#include <variant>

int main()
{
    variant<int, float, std::string> data; // data默认值为0
    data = 42;
    bool contains_int = holds_alternative<int>(data);
    bool contains_float = holds_alternative<float>(data);
    std::cout << data.index() << contains_int << contains_float 
              << get<0>(data) << *get_if<0>(&data) << std::endl; // 10142
    data = 3.14f;
    std::cout << data.index() << (get_if<int>(&data) == nullptr) 
              << get<1>(data) << get<float>(data) << std::endl; // 113.143.14
    data = "Hello";
    std::cout << data.index() << get<2>(data) << get<std::string>(data) << std::endl; // 2HelloHello
}

std::visit函数

std::visit(visitor, var)将variant中存储的数据作为参数传递给访问者函数visitor。 对于多个variant,std::visit(visitor, var1, var2, ...)会将所有variant中存储的数据作为参数传递给访问者函数。

#include <iostream>
#include <string>
#include <variant>
#include <boost/hana/functional/overload.hpp>

struct DataVisitor {
    void operator()(int number) const {
        std::cout << "整数: " << number << std::endl;
    }
    void operator()(double decimal) const {
        std::cout << "浮点数: " << decimal << std::endl;
    }
    void operator()(const std::string& text) const {
        std::cout << "字符串: " << text << std::endl;
    }
};

template<typename... Funcs> struct MultiVisitor : Funcs... { 
    using Funcs::operator()...; 
};
template<typename... Funcs> MultiVisitor(Funcs...) -> MultiVisitor<Funcs...>;
 
int main()
{
    variant<int, double, std::string> container;
    
    // 使用lambda作为访问者
    auto lambda_visitor = [](const auto& value) { 
        std::cout << value << std::endl; 
    };
    
    // 使用函数对象作为访问者
    DataVisitor function_visitor;
    
    // 使用重载lambda作为访问者
    MultiVisitor overloaded_visitor{
        [](int num){std::cout << "整数: " << num << std::endl;},
        [](double dbl){std::cout << "浮点数: " << dbl << std::endl;},
        [](const std::string& str){std::cout << "字符串: " << str << std::endl;}
    };
    
    // 使用boost::hana::overload创建访问者
    auto hana_visitor = boost::hana::overload(
        [](int num){std::cout << "整数: " << num << std::endl;},
        [](double dbl){std::cout << "浮点数: " << dbl << std::endl;},
        [](const std::string& str){std::cout << "字符串: " << str << std::endl;}
    );
    
    // 使用编译期if的lambda访问者
    auto conditional_visitor = [](const auto& arg) { 
        using ValueType = std::decay_t<decltype(arg)>; 
        if constexpr (std::is_same_v<ValueType, int>) {
            std::cout << "整数: " << arg << std::endl;
        }
        else if constexpr (std::is_same_v<ValueType, double>) {
            std::cout << "浮点数: " << arg << std::endl;
        }
        else if constexpr (std::is_same_v<ValueType, std::string>) {
            std::cout << "字符串: " << arg << std::endl;
        }
    };
    
    container = 100;
    std::visit(lambda_visitor, container);
    std::visit(function_visitor, container);
    std::visit(overloaded_visitor, container);
    std::visit(hana_visitor, container);
    std::visit(conditional_visitor, container);
    
    container = 3.14;
    std::visit(lambda_visitor, container);
    std::visit(function_visitor, container);
    std::visit(overloaded_visitor, container);
    std::visit(hana_visitor, container);
    std::visit(conditional_visitor, container);
    
    container = "World";
    std::visit(lambda_visitor, container);
    std::visit(function_visitor, container);
    std::visit(overloaded_visitor, container);
    std::visit(hana_visitor, container);
    std::visit(conditional_visitor, container);
}
  • lambda_visitor和conditional_visitor是泛型lambda,可以接受任何类型参数。
  • lambda_visitor不区分参数类型。
  • conditional_visitor使用编译期if语句来区分参数类型。
  • function_visitor和overloaded_visitor是函数对象,通过重载函数调用操作符来区分参数类型。
  • function_visitor的函数调用操作符在自身中定义。
  • overloaded_visitor的函数调用操作符继承自三个lambda。
  • hana_visitor通过boost::hana::overload函数生成,能够从多个lambda中选择合适的处理指定参数。
  • 代码示例中使用了三个C++17新特性:
  • 类模板的自动推导指引
  • 变长using声明
  • 编译期if语句

相关文章

Trojan服务器搭建与配置

一、整体架构(先对齐认知)Clash Meta (PC / iOS / Android)        ↓ TLS   Trojan Server (443)        ↓     InternetTrojan 的核心是: TLS + HTTPS 流量伪装 看起来像正常网站 非常适合...

Tailscale 的详细用法

Tailscale 是一种基于 WireGuard 协议 的 零配置 VPN(虚拟私有网络)服务,让设备之间能够 安全、加密地直接连接,就像它们在同一个本地网络一样。它的核心特点是 简单、安全、跨平台。Tailscale 非常适合 没有公网 IP、两台电脑不在同一局域网 的场景。 简单来说,Tailscale 是什么?Tailscale 是一款让你的各种设备(电脑、服务器、手机...

Clash Tun 模式 导致 爱快(iKuai SD-Wan)内网域名无法访问

一、Clash  DNS 配置dns:  enable: true  listen: 0.0.0.0:53  ipv6: true  enhanced-mode: redir-host  nameserver:    - 223.5.5.5    - 223.6.6.6iKuai 内网域名 ...

深入解析Node.js运行环境与异步I/O架构

深入解析Node.js运行环境与异步I/O架构

核心定义与价值Node.js本质上是一个JavaScript运行环境,而非编程语言或应用框架。它赋予了JavaScript脱离浏览器在服务端、命令行工具及网络应用中执行的能力。其核心意义在于:用单一语言打通前后端开发壁垒。基于事件驱动与非阻塞I/O的架构特性,Node.js在处理API网关、实时通信及微服务等I/O密集型场景时表现卓越,已成为现代后端工程的主流选择。浏览器沙箱限制1995年Java...

ADO.NET SQL参数化查询的最佳实践

在 ADO.NET 中执行 SQL 查询时,参数化查询是一种关键的安全措施和性能优化手段。它通过将 SQL 命令和用户提供的数据分开处理,有效防止了 SQL 注入攻击,并有助于数据库缓存执行计划。下面总结了几种常用的参数化查询方式。 1. 使用 SqlParameter 对象(推荐) 这是最推荐的参数化查询方式。通过显式创建 SqlParameter 对象,您可以精确控制参数的类...

基于ELK的日志集中化分析系统搭建

构建统一日志管理平台的必要性 在分布式架构中,各服务节点独立运行,日志分散存储于不同主机。传统通过命令行工具如grep、awk逐个检索日志的方式,在数据量庞大时效率极低,难以实现快速定位问题。为提升运维效率,需建立集中式日志处理体系,具备日志采集、传输、存储、分析与告警能力。 ELK技术栈核心组件解析 Elasticsearch:分布式搜索引擎,支持全文检索、实时数据分析和高可用集群部署,...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。