广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++17之std::visit的具体使用
  • 737
分享到

C++17之std::visit的具体使用

2024-04-02 19:04:59 737人浏览 独家记忆
摘要

目录1. 使用对象函数方式访问 2. 使用泛型Lambdas访问3. 使用重载的Lambdas来访问    它们必须明确地为每种可能的类型提供函数调用操

    它们必须明确地为每种可能的类型提供函数调用操作符。然后,使用相应的重载来处理当前的备选项类型。

1. 使用对象函数方式访问

例1:

#include <iOStream>
#include <variant>
#include <string>
 
struct MyVisitor
{
    void operator()(double d) const {
        std::cout << d << '\n';
    }
    void operator()(int i) const {
        std::cout << i << '\n';
    }
    void operator()(const std::string& s) const {
        std::cout << s << '\n';
}
};
int main()
{
    std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit");
 
    std::visit(MyVisitor(), var1); // calls operator() for matching int type
 
    std::visit(MyVisitor(), var2); // calls operator() for matching double type
 
    std::visit(MyVisitor(), var3); // calls operator() for matching std::string type
 
    return 0;
}

结果如下:

 如果操作符()不支持所有可能的类型,或者调用不明确,则visit()调用是编译时错误。还可以使用访问者修改当前类型的值(但不能分配新类型的值)。

例2:

#include <iostream>
#include <variant>
#include <string>
 
struct Twice
{
    void operator()(double& d) const {
        d *= 2;
    }
    void operator()(int& i) const {
        i *= 2;
    }
    void operator()(std::string& s) const {
        s = s + s;
    }
};
 
int main()
{
    std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit");
 
    std::visit(Twice(), var1); // calls operator() for matching int type
 
    std::visit(Twice(), var2); // calls operator() for matching double type
 
    std::visit(Twice(), var3); // calls operator() for matching std::string type
 
    std::cout << std::get<int>(var1) << std::endl;
    std::cout << std::get<double>(var2) << std::endl;
    std::cout << std::get<std::string>(var3) << std::endl;
 
    return 0;
}

结果如下:

注意,对象操作符应该为const函数,因为它们是无状态的(它们不改变它们的行为,只改变传递的值,即不改变成员变量的值)。 

 2. 使用泛型Lambdas访问

使用这个特性最简单的方法是使用泛型lambda,它是一个函数对象,用于任意类型:

例3:

#include <iostream>
#include <variant>
#include <string>
 
auto printvariant = [](const auto& val) 
{
    std::cout << val << std::endl;
};
 
int main()
{
    std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit");
 
    std::visit(printvariant, var1);
 
    std::visit(printvariant, var2);
 
    std::visit(printvariant, var3);
 
    return 0;
}

结果如下:

 这里,泛型lambda定义了一个闭包类型,其中函数调用操作符作为成员模板:

class CompilerSpecifyClosureTypeName 
{
public:
template<typename T>
auto operator() (const T& val) const 
{
    std::cout << val << '\n';
}
};

也可以使用lambda来修改当前选项的值:

例4:

#include <iostream>
#include <variant>
#include <string>
 
auto printvariant = [](const auto& val)
{
    std::cout << val << std::endl;
};
 
int main()
{
    std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit");
 
    std::visit([](auto& val) {
        val = val + val;
        },
        var1);
    std::visit([](auto& val) {
        val = val + val;
        },
        var2);
    std::visit([](auto& val) {
        val = val + val;
        },
        var3);
 
    std::visit(printvariant, var1);
    std::visit(printvariant, var2);
    std::visit(printvariant, var3);
 
    return 0;
}

结果如下:

甚至可以使用编译时if语言特性以不同的方式处理不同的备选值:

例5:

#include <iostream>
#include <variant>
#include <string>
 
auto dblvar = [](auto& val)
{
    if constexpr (std::is_convertible_v<decltype(val), std::string>)
    {
        val = val + " test";
    }
    else
    {
        val += 2;
    }
};
 
int main()
{
    std::variant<int, double, std::string> var1(42), var2(3.14), var3("visit");
 
    std::visit(dblvar, var1);
    std::visit(dblvar, var2);
    std::visit(dblvar, var3);
 
    std::cout << std::get<int>(var1) << std::endl;
    std::cout << std::get<double>(var2) << std::endl;
    std::cout << std::get<std::string>(var3) << std::endl;
 
    return 0;
}

这里,对于一个std::string类型备选项,泛型lambda的调用实例化它的泛型函数调用模板来计算:

val = val + “ test”;

而对于其他类型备选项,如int或double, lambda的调用实例化其通用函数调用模板来计算:

val += 2;

结果如下:

3. 使用重载的Lambdas来访问

通过为函数对象和lambdas使用一个重载器,还可以定义一组lambdas,其中使用最佳匹配作为访问者。假设,重载器定义为重载,如下所示:

template<typename... Ts>
struct overload : Ts...
{
using Ts::operator()...;
};
// base types are deduced from passed arguments:
template<typename... Ts>
overload(Ts...) -> overload<Ts...>;

可以使用重载访问一个变量,为每个选项提供lambdas:

std::variant<int, std::string> var(42);
...
std::visit(overload{ // calls best matching lambda for current alternative
[](int i) { std::cout << "int: " << i << '\n'; },
[](const std::string& s) {
std::cout << "string: " << s << '\n'; },
},
var);

还可以使用泛型lambda。总是用最好的搭配。例如,要修改variant对象的当前类型备选项的值,可以使用重载将字符串和其他类型的值“加倍”:

auto twice = overload{
[](std::string& s) { s += s; },
[](auto& i) { i *= 2; },
};

    使用此重载,对于字符串类型备选项,将添加当前值,而对于所有其他类型,将值乘以2,这演示了variant对象的以下应用程序:

std::variant<int, std::string> var(42);
std::visit(twice, var); // value 42 becomes 84
...
var = "hi";
std::visit(twice, var); // value "hi" becomes "hihi"

例 6:

#include <iostream>
#include <variant>
#include <string>
 
template<typename... Ts>
struct overload : Ts...
{
    using Ts::operator()...;
};
 
template<typename... Ts>
overload(Ts...)->overload<Ts...>;
 
auto twice = overload{
        [](std::string& s) { s += s; },
        [](auto& i) { i *= 2; },
};
 
int main()
{
    std::variant<int, std::string> var1(42) , var3("visit");
 
    std::visit(twice, var1);
    std::visit(twice, var3);
    
    std::visit(overload{ // calls best matching lambda for current alternative
        [](int i) { std::cout << "int: " << i << '\n'; },
        [](const std::string& s) {
        std::cout << "string: " << s << '\n'; },
        },
        var1);
    
    std::visit(overload{ // calls best matching lambda for current alternative
       [](int i) { std::cout << "int: " << i << '\n'; },
       [](const std::string& s) {
       std::cout << "string: " << s << '\n'; },
        },
        var3);
    
    return 0;
}

结果如下:

 到此这篇关于c++17之std::visit的具体使用的文章就介绍到这了,更多相关C++17 std::visit内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++17之std::visit的具体使用

本文链接: https://www.lsjlt.com/news/138220.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++17之std::visit的具体使用
    目录1. 使用对象函数方式访问 2. 使用泛型Lambdas访问3. 使用重载的Lambdas来访问    它们必须明确地为每种可能的类型提供函数调用操...
    99+
    2022-11-13
  • C++17之std::any的具体使用
    目录1. 使用std::any 2. std::any类型和操作2.1 std::any的类型2.2 std::any操作    一般来说,c++是一种...
    99+
    2022-11-13
  • C++的std::visit如何使用
    这篇文章主要介绍“C++的std::visit如何使用”,在日常操作中,相信很多人在C++的std::visit如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++的std::visit如何使用”的疑...
    99+
    2023-06-29
  • C++17使用std::optional表示可能存在的值
    目录前言返回一个bool值使用 std::optional 改写总结前言 平时写代码会遇到一种传递参数特殊值标记特殊流程,或者函数返回值存在魔法数的情况,很需要一种标记参数或返回值状...
    99+
    2022-11-13
  • C++智能指针之shared_ptr的具体使用
    目录std::shared_ptr概念shared_ptr模板类shared_ptr的构造和析构shared_ptr赋值make_shared计数线程安全?enable_shared...
    99+
    2022-11-13
  • C++11之std::future对象的使用以及说明
    目录std::future介绍细节说明wait系列操作get操作时序图std::future使用总结std::future介绍 在前面几篇文章中基本都用到thread对象,它是C++...
    99+
    2023-02-28
    C++11 std::future std::future对象 std::future对象使用
  • C# Volatile的具体使用
    目录​1.Overview2.Detail3.Conclusion4.Reference​1.Overview 经常研究.NET源码库的小伙伴会经常看到一个关...
    99+
    2022-11-12
  • python3之Splash的具体使用
    目录1、Scrapy-Splash的安装2、Splash Lua脚本3、Splash对象的属性与方法4、响应对象5、元素对象6、Splash HTTP API调用7、实例Splash...
    99+
    2022-11-12
  • nginx之queue的具体使用
    目录一、简介二、数据结构三、相关API3.1 初始化一个队列3.2 判断队列是否为空3.3 队头插入节点3.4 队尾插入节点3.5 从队列中移除某个节点3.6 将队列从某个节点拆分成...
    99+
    2022-11-13
  • C++ deque容器的具体使用
     deque 是 double-ended queue 的缩写,又称双端队列容器。 和 vector 不同的是,deque 还擅长在序列头部添加或删除元素,所耗费的时间复杂...
    99+
    2022-11-12
  • C# goto语句的具体使用
    C# goto 语句用于直接在一个程序中转到程序中的标签指定的位置,标签实际上由标识符加上冒号构成。 语法形式如下。 goto Labell; 语句块 1; Labell...
    99+
    2022-11-12
  • C#中{get;set;}的具体使用
    在C#程序中经常会看到set,get的配套使用,很多人不知道它的用途。我就在这向大家讲讲,也加深一下自己的印象。 //这里有两个类 public class person1 { ...
    99+
    2023-02-06
    C# {get;set;} C# GET SET
  • C#Replace替换的具体使用
    目录前言一、String.Replace() 的几个重载1、Replace(Char, Char)2、String.Replace(String, String) ...
    99+
    2023-02-19
    C# Replace替换 C# Replace
  • C++ setw()函数的具体使用
    C++ setw() 函数用于设置字段的宽度,语法格式如下: setw(n) n 表示宽度,用数字表示。 setw() 函数只对紧接着的输出产生作用。 当后面紧跟着的输出字段长度小...
    99+
    2023-03-09
    C++ setw()
  • C++11新特性之列表初始化的具体使用
    目录统一的初始化方法列表初始化的一些使用细节初始化列表1、任何长度的初始化列表2、std::initialzer-list的使用细节列表初始化防止类型收窄在我们实际编程中,我们经常会...
    99+
    2022-11-13
  • C/C++QtToolBar菜单组件的具体使用
    ToolBar工具栏在所有窗体应用程序中都广泛被使用,使用ToolBar可以很好的规范菜单功能分类,用户可根据菜单栏来选择不同的功能,Qt中默认自带ToolBar组件,当我们以默认方...
    99+
    2022-11-12
  • C/C++QtQChart绘图组件的具体使用
    QtCharts 组件是QT中提供图表绘制的模块,该模块可以方便的绘制常规图形,Qtcharts 组件基于GraphicsView模式实现,其核心是QChartView和QChart...
    99+
    2022-11-12
  • C/C++QtQThread线程组件的具体使用
    QThread库是QT中提供的跨平台多线程实现方案,使用时需要继承QThread这个基类,并重写实现内部的Run方法,由于该库是基本库,默认依赖于QtCore.dll这个基础模块,在...
    99+
    2022-11-12
  • C语言结构体指针的具体使用
    目录什么是结构体指针?如何访问结构体成员?如何传递结构体指针作为参数?结构体指针数组在 C语言中,结构体指针是一种非常有用的数据类型,它可以让我们更方便地操作结构体。结构体指针可以指...
    99+
    2023-05-20
    C语言结构体指针
  • C语言结构体的具体使用方法
    目录初识C语言结构体1.为什么要有结构体2.结构体的定义2.1结构体类型的定义2.2定义结构体普通变量及访问2.3定义结构体指针变量及访问初识C语言结构体 1.为什么要有结构体 (1...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作