variant

variant 是 C++17 所提供的变体类型。variant<X, Y, Z> 是可存放 X, Y, Z 这三种类型数据的变体类型。

  • 与C语言中传统的 union 类型相同的是,variant 也是联合(union)类型。即 variant 可以存放多种类型的数据,但任何时刻最多只能存放其中一种类型的数据。
  • 与C语言中传统的 union 类型所不同的是,variant 是可辨识的类型安全的联合(union)类型。即 variant 无须借助外力只需要通过查询自身就可辨别实际所存放数据的类型。

v = variant<int, double, std::string> ,则 v 是一个可存放 int, double, std::string 这三种类型数据的变体类型的对象。

  • v.index() 返回变体类型 v 实际所存放数据的类型的下标。

    变体中第1种类型下标为0,第2种类型下标为1,以此类推。
  • std::holds_alternative<T>(v) 可查询变体类型 v 是否存放了 T 类型的数据。
  • std::get<I>(v) 如果变体类型 v 存放的数据类型下标为 I,那么返回所存放的数据,否则报错。

    std::get_if<I>(&v) 如果变体类型 v 存放的数据类型下标为 I,那么返回所存放数据的指针,否则返回空指针。
  • std::get<T>(v) 如果变体类型 v 存放的数据类型为 T,那么返回所存放的数据,否则报错。

    std::get_if<T>(&v) 如果变体类型 v 存放的数据类型为 T,那么返回所存放数据的指针,否则返回空指针。
#include <iostream>
#include <string>
#include <variant> using namespace std; int main()
{
variant<int, double, string> v; // v == 0
v = 1;
bool has_int = holds_alternative<int>(v);
bool has_double = holds_alternative<double>(v);
cout << v.index() << has_int << has_double << get<0>(v) << *get_if<0>(&v) << endl; // 01011
v = 2.0;
cout << v.index() << (get_if<int>(&v) == nullptr) << get<1>(v) << get<double>(v) << endl; // 1122
v = "a";
cout << v.index() << get<2>(v) << get<string>(v) << endl; // 2aa
}

std::visit

std::visit(f, v) 将变体类型 v 所存放的数据作为参数传给函数 f。

std::visit(f, v, u) 将变体类型 v, u 所存放的数据作为参数传给函数 f。

...

std::visit 能将所有变体类型参数所存放的数据作为参数传给函数参数。

#include <iostream>
#include <string>
#include <variant>
#include <boost/hana/functional/overload.hpp> using namespace std;
namespace hana = boost::hana; struct Visitor {
void operator()(int n) const {
cout << "int: " << n << endl;
}
void operator()(double d) const {
cout << "double: " << d << endl;
}
void operator()(const string& s) const {
cout << "string: " << s << endl;
}
}; template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; int main()
{
variant<int, double, string> v; // v == 0
auto f = [](auto& x) {cout << x << endl;};
Visitor f2;
overloaded f3{
[](int n){cout << "int: " << n << endl;},
[](double d){cout << "double: " << d << endl;},
[](const string& s){cout << "string: " << s << endl;}
};
auto f4 = hana::overload(
[](int n){cout << "int: " << n << endl;},
[](double d){cout << "double: " << d << endl;},
[](const string& s){cout << "string: " << s << endl;}
);
auto f5 = [](auto& arg) { using T = decay_t<decltype(arg)>;
// auto f5 = []<typename T>(T& arg) { // C++ 20
if constexpr (is_same_v<T, int>) {
cout << "int: " << arg << endl;
}
else if constexpr (is_same_v<T, double>) {
cout << "double: " << arg << endl;
}
else if constexpr (is_same_v<T, string>) {
cout << "string: " << arg << endl;
}
};
v = 1; visit(f, v); visit(f2, v); visit(f3, v); visit(f4, v); visit(f5, v); // 1 int: 1 int: 1 int: 1 int: 1
v = 2.0; visit(f, v); visit(f2, v); visit(f3, v); visit(f4, v); visit(f5, v); // 2 double: 2 double: 2 double: 2 double: 2
v = "a"; visit(f, v); visit(f2, v); visit(f3, v); visit(f4, v); visit(f5, v); // a string: a string: a string: a string: a
}
  • f 和 f5 是泛型 lambda,接受所有参数的类型。

    f 不分辨参数类型。

    f5 通过编译期 if 语句来分辨参数类型。
  • f2 和 f3 是函数对象,通过重载函数调用操作符来分辨参数的类型。

    f2 的函数调用操作符由自身定义。

    f3 的函数调用操作符继承自3个lambda。
  • f4 这个函数对象经由 boost::hana::overload 函数生成,该函数所生成的函数对象能从多个lambda参数中选取一个合适的来调用指定参数。
  • 这段代码总共使用了三个C++17的新特性:

    适用于类模板的自动推断向导 https://www.cnblogs.com/zwvista/p/7748363.html

    变长 using 声明 https://www.cnblogs.com/zwvista/p/9256655.html

    编译期 if 语句 https://www.cnblogs.com/zwvista/p/9238273.html

C++17尝鲜:variant的更多相关文章

  1. C++17尝鲜

    https://cloud.tencent.com/developer/article/1351910 [译]C++17,optional, any, 和 variant 的更多细节 用户261520 ...

  2. C++17尝鲜:变长 using 声明

    using 声明 先来看 using 声明在类中的应用: 代码1 #include <iostream> using namespace std; struct A { void f(in ...

  3. C++17尝鲜:编译期 if 语句

    Constexpr If(编译期 if 语句) 以 if constexpr 打头的 if 语句被称为 Constexpr If. Constexpr If 是C++17所引入的新的语法特性.它为C+ ...

  4. C++17尝鲜:string_view

    string_view string_view 是C++17所提供的用于处理只读字符串的轻量对象.这里后缀 view 的意思是只读的视图. 通过调用 string_view 构造器可将字符串转换为 s ...

  5. C++17尝鲜:结构化绑定声明(Structured Binding Declaration)

    结构化绑定声明 结构化绑定声明,是指在一次声明中同时引入多个变量,同时绑定初始化表达式的各个子对象的语法形式. 结构化绑定声明使用auto来声明多个变量,所有变量都必须用中括号括起来. cv-auto ...

  6. C++17尝鲜:类模板中的模板参数自动推导

    模板参数自动推导 在C++17之前,类模板构造器的模板参数是不能像函数模板的模板参数那样被自动推导的,比如我们无法写 std::pair a{1, "a"s}; // C++17 ...

  7. C++17尝鲜:在 if 和 switch 语句中进行初始化

    初始化语句 在C++17中,类似于 for 语句,在 if 和 switch 语句的判断条件之前也能加上初始化语句,语法形式如下: if (初始化语句; 条件) 语句 else 语句 switch ( ...

  8. 带你尝鲜LiteOS 组件EasyFlash

    摘要:EasyFlash是一个开源的轻量级嵌入式闪存库. 本文分享自华为云社区<LiteOS组件尝鲜-玩转EasyFlash>,作者:Lionlace . 基本介绍 EasyFlash是一 ...

  9. JEP解读与尝鲜系列4 - Java 16 中对于 Project Valhalla 的铺垫

    这是 JEP 解读与尝鲜系列的第 4 篇,之前的文章如下: JEP解读与尝鲜系列 1 - Java Valhalla与Java Inline class JEP解读与尝鲜系列 2 - JEP 142 ...

随机推荐

  1. Authentication required (packagist.phpcomposer.com) 账号密码到哪里获取?

    安装好composer后,执行composer install 报这个错 面对这个错有两种方法.1,他说你的composr 版本不够稳定,composer update 一下,或者 composer ...

  2. Socket的长连接和短连接

    讨论Socket必讨论长连接和短连接 一.长连接和短连接的概念 1.长连接与短连接的概念:前者是整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接:后者是每次请求,都新建 ...

  3. redis作为mysql的缓存服务器(读写分离)

    转自:https://www.iyunv.com/thread-52670-1-1.html 一.redis简介Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据 ...

  4. ubuntu 16.04在真实机安装后的静态ip的配置

    nssa-sensor1@nssa-sensor1:~$ vim /etc/network/interfaces 以下是编辑文件的内容# interfaces(5) file used by ifup ...

  5. SQL Server 导入超大脚本

    另外使用window server 版操作系统,执行脚本文件比普通版操作系统大大提升大小限制. 在执行SQL脚本的时候要是出现了这些情况我咋办呢? 步入正轨 应用场景:服务器升级,比如原来是2003的 ...

  6. jQuery实现鼠标滑过图片列表加遮罩层

    这个例子实现的功能是:有一列图片列表,鼠标滑过时,将有遮罩层的另一张图盖在该图片的上方,实现鼠标hover的效果. 一.HTML代码: <div class="home-content ...

  7. 浅谈jmeter请求参数获取的方式

    一.传统的web端请求参数我们在浏览器url栏看到传递的参数是什么,比如百度: 1.我们假如百度有一个这样的地址: https://www.baidu.com/s?wd=jmeter&name ...

  8. c# 枚举的定义,枚举的用法,获取枚举值

    1.定义枚举类型 public enum Test { 男 = , 女 = } 2.获取枚举值 public void EnumsAction() { var s = Test.男;//男 var a ...

  9. 重识linux-linux系统服务相关

    重识linux-linux系统服务相关 1 tcp wrappers 特殊功能  应用级防火墙 2 系统开启的服务查看 top,ps 命令 3 查看系统启动的服务 1) 找到目前系统开启的网络服务 n ...

  10. tomcat7的一些设置(修改内存)

    1.内存修改.今天在tomcat7下面部署了两个项目.居然报错了. 然后开始打开Tomcat7w.exe 在java标签中的initial memory pool和muxinum memory poo ...