【C++】optional的使用(一)

这篇文章介绍下C++17引入的std::optional

为什么要有 optional

一般来说,如果想要一个函数返回“多个”值,C++程序员倾向于使用结构体/类完成这个操作。即定义一个通用的结构体,在函数内部完成装填,然后返回一个实例化的结构体。

#include <iostream>

using namespace std;

struct Out {
    string out1 { "" };
    string out2 { "" };
};

pair<bool, Out> func(const string& in) {
    Out o;
    if (in.size() == 0)
        return { false, o };
    o.out1 = "hello";
    o.out2 = "world";
    return { true, o };
}

int main() {
    if (auto [status, o] = func("hi"); status) {
        cout << o.out1 << endl;
        cout << o.out2 << endl;
    }
    return 0;
}

(代码来自 https://zhuanlan.zhihu.com/p/64985296)

C++17引入了std::optional,介绍如下:

The class template std::optional manages an optional contained value,
i.e. a value that may or may not be present. A common use case for
optional is the return value of a function that may fail. As opposed
to other approaches, such as std::pair<T,bool>, optional handles
expensive-to-construct objects well and is more readable, as the
intent is expressed explicitly. 类模板 std::optional
管理一个可选的容纳值,即可以存在也可以不存在的值。 一种常见的 optional 使用情况是一个可能失败的函数的返回值。与其他手段,如
std::pair<T,bool> 相比, optional 良好地处理构造开销高昂的对象,并更加可读,因为它显式表达意图。

换句话说,一个普通的变量,只有不同的值。而optional相当于在外面套了一层壳,先考虑存不存在值,再考虑值是多少。

使用

对于像我这样的菜鸟来说,optional 的源代码十分复杂的。但是使用起来并不困难,理解上面的含义就行。

  /**
    * @brief Class template for optional values.
    */
  template<typename _Tp>
    class optional
    : private _Optional_base<_Tp>,
      private _Enable_copy_move<
	// Copy constructor.
	is_copy_constructible_v<_Tp>,
	// Copy assignment.
	__and_v<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>,
	// Move constructor.
	is_move_constructible_v<_Tp>,
	// Move assignment.
	__and_v<is_move_constructible<_Tp>, is_move_assignable<_Tp>>,
	// Unique tag type.

可以看到,本质上其实是个模板类,将包裹的类型以模板参数T的方式传入。

初始化

optional几种初始化如下:

    //初始化为空
    optional<int> int_empty;
    //使用有效值初始化(C++其他初始化方法也同样可用)
    optional<int> my_int = 2;
    //使用make_optional
    auto doubleOpt = std::make_optional(10.0);
    auto complexOpt = std::make_optional<std::complex<double>>(3.0, 4.0);
    //使用in_place
    optional<vector<int>> vectorOpt{in_place, {1, 2, 3}};
    //使用其它optional对象复制/移动构造
    auto optCopied = vectorOpt;

说一下第三点和第四点,就是这个std::make_optionalstd::in_place。我搜到的资料显示这代表直接调用模板T的构造函数,即“完美转发”。

假设我有这么一个类 TestOp:

struct TestOp
{
    TestOp() : age(100) {}
    int getAge() { return age; }

private:
    int age;
};

它有一个无参数的构造函数,但这个构造函数为成员赋默认值。这时,若使用如下写法

    optional<TestOp> test_op;
    cout << test_op.value().getAge() << endl;

会编译失败。因为optional并不会调用TestOp的默认构造函数,只会创建一个空的TestOp对象。
编译失败
这让我非常不理解,因为就算是未传入参数,应该调用T的默认构造函数才对。
你可能想到,如果初始化时直接传入构造函数呢?

    optional<TestOp> test_op{TestOp()};

这样写当然没问题,我们将得到包含默认TestOp对象的optional对象。但是在上面的代码中,将先构造出一个TestOp的临时对象,然后调用move函数将这个临时对象“移动”到optional存储的对象中,带来了额外的开销。在这种情况下,我们就只能使用std::in_place/ std::make_optional来“原地”构造optional底层存储的对象。

另一种情况是,TestOp禁用了移动构造和复制构造函数,这时候也只能用std::in_place/ std::make_optional

最后一种必须使用std::in_place/ std::make_optional的情况是,当你需要使用多个参数初始化同一个变量时,比如std::vector。没错,原生的 optional构造函数,并不支持多参数,神奇吧?
6
我猜想多参数的支持会导致歧义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/251788.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决PP材质粘合问题用PP专用UV胶水

PP材料已经广泛应用于各行各业&#xff0c;在粘接中会有不同的问题需求&#xff0c;那么使用专用于PP的UV胶水可能是解决PP材质粘合问题的一种有效方法。 主要在于&#xff1a;UV胶水在紫外线照射下可以快速固化&#xff0c;形成坚固的连接。所以使用PP专用UV胶水时可以考虑&am…

oracle Job 定时任务

目录 介绍&#xff1a; 优点&#xff1a; 缺点&#xff1a; 使用场景&#xff1a; --查看定时任务 --查询存储过程 案例&#xff1a; --创建一个名为t_oracle_job的表 在创建定时任务时&#xff0c;各个参数的含义如下&#xff1a; 1. job_name&#xff1a…

day02-报表技术POI

1、基于模板导出列表数据 1.1、需求 按照以下样式导出excel 1.2、思路 首先准备一个excel模板&#xff0c;这个模板把复杂的样式和固定的内容先准备好并且放入到项目中&#xff0c;然后读取到模板后向里面放入数据。 1.3、实现 第一步&#xff1a;准备一个excel作为导出的…

【ArkTS】入门

代码结构分析 struct Index{ } 「自定义组件&#xff1a;可复用的UI单元」 xxx 「装饰器&#xff1a;用来装饰类结构、方法、变量」 Entry 标记当前组件是入口组件&#xff08;该组件可被独立访问&#xff0c;通俗来讲&#xff1a;它自己就是一个页面&#xff09;Component 用…

LeetCode-克服链表不能随机访问的问题

1.重排链表 题目描述&#xff1a; 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为&#xff1a; L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值&#xff0…

解决vue3+ts打包,ts类型检查报错导致打包失败

最近拉的开源大屏项目goview&#xff0c;在打包的过程中一直报Ts类型报错导致打包失败&#xff0c;项目的打包命令为&#xff1a; "build": "vue-tsc --noEmit && vite build" 是因为 vue-tsc --noEmit 是 TypeScript 编译器&#xff08;tsc&#…

python 基于imageio_ffmpeg 直接操作ffmpeg,无需额外在官网下载!

python直接操作ffmpeg&#xff0c;无需在官网下载&#xff01; 一、前言 在要使用ffmpeg处理的时候&#xff0c;不想去官网下载ffmpeg然后添加到环境变量再使用。研究了一下&#xff0c;可以通过下面的方法解决 imageio_ffmpeg subprocess 二、具体步骤 1、环境配置 pip i…

报数游戏C语言

分析:掌握数字移动的规律&#xff0c;以及判断&#xff0c;我们可以用一个二维数组来记录每一个人说的数字&#xff0c;就像第一张图片一样&#xff0c;西安向右边移动&#xff0c;再向左下移动&#xff0c;再向左边移动&#xff0c;在向右边移动&#xff0c;在可以用一个数组来…

pytorch强化学习(1)——DQNSARSA

实验环境 python3.10 torch2.1.1 gym0.26.2 gym[classic_control] matplotlib3.8.0 numpy1.26.2DQN代码 首先是module.py代码&#xff0c;在这里定义了网络模型和DQN模型 import torch import torch.nn as nn import numpy as npclass Net(nn.Module):# 构造只有一个隐含层的…

Zabbix监控系统部署与管理

目录 zabbix介绍 zabbix构成 zabbix进程 环境 zabbix-server节点部署 安装zabbix服务 安装与配置数据库 修改zabbix-PHP时区 登录网页安装 ​编辑数据库Access denied故障 zabbix-agent节点部署 zabbix web管理 中文乱码问题 zabbix介绍 zabbix是⼀个基于 Web 界…

【人工智能】实验二: 洗衣机模糊推理系统实验与基础知识

实验二: 洗衣机模糊推理系统实验 实验目的 理解模糊逻辑推理的原理及特点&#xff0c;熟练应用模糊推理。 实验内容 设计洗衣机洗涤时间的模糊控制。 实验要求 已知人的操作经验为&#xff1a; “污泥越多&#xff0c;油脂越多&#xff0c;洗涤时间越长”&#xff1b;“…

如何使用ycsb工具对mongodb进行性能测试过程

测试环境&#xff1a; linux系统&#xff1a;Centos 7.2 ,版本&#xff1a;Red Hat 4.8.5-44) YCSB简介 ycsb是一款性能测试工具&#xff0c;用Java写的&#xff0c;并且什么都可以压&#xff0c;像是mongodb&#xff0c;redis&#xff0c;mysql&#xff0c;hbase&#xff0c;等…

JavaScript值类型和引用类型两道经典面试题

JavaScript值类型和引用类型两道经典面试题 题目1题目2 题目1 首先&#xff0c;小试牛刀&#xff0c;请看第一道题。 let a {x: 10 } let b a a.x 20 console.log(b.x)a {x: 30 } console.log(b.x) a.x 40 console.log(b.x);那么上述代码输出结果是多少呢&#xff1f; …

逻辑分析仪_使用手册

LA1010 1> 能干啥&#xff1f;2> 硬件连接3> 软件安装4> 参数设置4.1> 采样深度和采样率4.2> 添加协议解析器4.3> 毛刺过滤设置 1> 能干啥&#xff1f; 测量通信波形&#xff0c;并自动解析&#xff1b; 比如测量&#xff0c;UART&#xff0c;SPI&…

Java系列-ConcurrentHashMap-addCount

1.addCount public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>implements ConcurrentMap<K,V>, Serializable {private final void addCount(long x, int check) {CounterCell[] as; long b, s;//1.counterCells不为null//2.或者 x加到baseCou…

如何在Docker部署draw.io流程图软件并实现公网远程访问

前言 提到流程图&#xff0c;大家第一时间可能会想到Visio&#xff0c;不可否认&#xff0c;VIsio确实是功能强大&#xff0c;但是软件为收费&#xff0c;并且因为其功能强大&#xff0c;导致安装需要很多的系统内存&#xff0c;并且是不可跨平台使用。所以&#xff0c;今天给…

深入学习《大学计算机》系列之第1章 1.3节——计算机科学的知识领域

一.欢迎来到我的酒馆 第1章 1.3节&#xff0c;计算机科学的知识领域。 目录 一.欢迎来到我的酒馆二.计算机科学的知识领域1.什么是计算机科学 二.计算机科学的知识领域 什么是计算机科学&#xff1f;什么是计算机学科&#xff1f;计算机科学包含哪些知识领域&#xff1f; …

PyCharm控制台异常堆栈乱码问题解决

目录 1、问题描述2、问题原因3、问题解决 1、问题描述 PyCharm环境都已经配置成了UTF-8编码&#xff0c;控制台打印中文也不会出现乱码&#xff0c;但异常堆栈信息中如果有中文会出现中文乱码&#xff1a; 这种该怎么解决呢&#xff1f; 2、问题原因 未将PyCharm编码环境与项目…

接口自动化测试实操【设置断言思路】

1 断言设置思路 这里总结了我在项目中常用的5种断言方式&#xff0c;基本可能满足90%以上的断言场景&#xff0c;具体参见如下脑图&#xff1a; 在这里插入图片描述 下面分别解释一下图中的五种思路&#xff1a; 1&#xff09; 响应码 对于http类接口&#xff0c;有时开发人…

Python:Jupyter

Jupyter是一个开源的交互式计算环境&#xff0c;由Fernando Perez和Brian Granger于2014年创立。它提供了一种方便的方式来展示、共享和探索数据&#xff0c;并且可以与多种编程语言和数据格式进行交互。Jupyter的历史可以追溯到2001年&#xff0c;当时Fernando Perez正在使用P…