C++23中的新功能之expected和optional

一、std::optional

在前面用过c++17新推出的这个std::optional功能,它可以处理接口返回空值的情况,非常方便实用。但终究存在一个习惯的问题,大家会问,只是处理一个空值,多写一个这玩意儿意义不大,还是用方法吧。这种情况一定是大概率的发生。正如语言发展一样,一定要简单,而且功能还要强大。
标准委员会的大佬们一定也是这么想的,所以既然出现了可选项,是不是可以在这个可选项上做文章,吸引更多的开发者使用它呢?先看一个例子:


std::optional<int> GetData(int id)
{...}
return GetData(id).value_or(-3);

这样在处理一些异常情况时,开发者可以自己设定返回默认的值。这种形式,一般对开发者来说,是喜闻乐见的,少写个else(甚至可能更多),而且还容易理解。只要头脑中这种想法开了头,那么便无法挡住了。在C++23中提供了三个函数:add_then,tranform以及or_else。它们基本都符合上面所说的容易理解应用还增强了功能。看下面的例子:

#include <charconv>
#include <iomanip>
#include <iostream>
#include <optional>
#include <ranges>
#include <string>
#include <string_view>
#include <vector>std::optional<int> to_int(std::string_view sv)
{int r {};auto [ptr, ec] { std::from_chars(sv.data(), sv.data() + sv.size(), r) };if (ec == std::errc())return r;elsereturn std::nullopt;
}int main()
{using namespace std::literals;const std::vector<std::optional<std::string>> v{"1234", "15 foo", "bar", "42", "5000000000", " 5", std::nullopt, "-43"};for (auto&& x : v | std::views::transform([](auto&& o){// debug print the content of input optional<string>std::cout << std::left << std::setw(13)<< std::quoted(o.value_or("nullopt")) << " -> ";return o// if optional is nullopt convert it to optional with "" string.or_else([]{ return std::optional{""s}; })// flatmap from strings to ints (making empty optionals where it fails).and_then(to_int)// map int to int + 1.transform([](int n) { return n + 1; })// convert back to strings.transform([](int n) { return std::to_string(n); })// replace all empty optionals that were left by// and_then and ignored by transforms with "NaN".value_or("NaN"s);}))std::cout << x << '\n';
}

看一下运行结果:

"1234"        -> 1235
"15 foo"      -> 16
"bar"         -> NaN
"42"          -> 43
"5000000000"  -> NaN
" 5"          -> NaN
"nullopt"     -> NaN
"-43"         -> -42

看到这个代码会不会想到在Java等其它语言中的函数式编程(链式编程),add_then它们三个就可以搞定。既可以用transform来处理正常的,也可以用or_else处理异常的,一瓜可以多吃,以后C++编程也可以 拖一长列,不过这玩意儿太长了,还真是不好理解。
人的本性或许就是懒的,有人说是懒人改变了这个世界,不是没有道理。

二、std::expected

前面的value_or其实可以当成一种std::expected的特例,先看一下它的定义:

template< class T, class E >
class expected;

std::expected增加了一个形参E,它用来处理不符合常规的,也就是异常的值。std::expected相当于std::variant和std::optional的结合体。在C++中,一般是不推荐抛出异常的,但错误会常常发生,这时,std::expected期望着正常的状态,但在出现非期望的状态时,也可以通过一些方式来展现这些异常。
看一个例子:

#include <cmath>
#include <expected>
#include <iomanip>
#include <iostream>
#include <string_view>enum class parse_error
{invalid_input,overflow
};auto parse_number(std::string_view& str) -> std::expected<double, parse_error>
{const char* begin = str.data();char* end;double retval = std::strtod(begin, &end);if (begin == end)return std::unexpected(parse_error::invalid_input);else if (std::isinf(retval))return std::unexpected(parse_error::overflow);str.remove_prefix(end - begin);return retval;
}int main()
{auto process = [](std::string_view str){std::cout << "str: " << std::quoted(str) << ", ";if (const auto num = parse_number(str); num.has_value()){std::cout << "value: " << *num << '\n';// If num did not have a value, dereferencing num// would cause an undefined behavior, and// num.value() would throw std::bad_expected_access.// num.value_or(123) uses specified default value 123.}else if (num.error() == parse_error::invalid_input){std::cout << "error: invalid input\n";}else if (num.error() == parse_error::overflow){std::cout << "error: overflow\n";}else{std::cout << "unexpected!\n"; // or invoke std::unreachable();}};for (auto src: { "42", "42abc", "meow", "inf" })process(src);
}

运行结果:

str: "42", value: 42
str: "42abc", value: 42
str: "meow", error: invalid input
str: "inf", error: overflow

而且它也有和std::optional一样的三个函数:add_then,tranform以及or_else,用法也基本相同。这个用在有多处判断返回结果处理异常的情况,就很有优势。

三、总结

库的强大,其实就意味着这种语言向简单化在发展。为什么Java等语言编写起来相对简单,主要原因就是除有强大的库,还有无数的可以看作库的框架。C++在这方面几乎没法和这些高级语言相比,但总体上C++也在朝着这个方向不断的前进,这就是好事。
或许再过十年,当开发者们回头看C++代码时,可能发现,这是我初学时的C++么?

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自然语言处理(四):全局向量的词嵌入(GloVe)

全局向量的词嵌入&#xff08;GloVe&#xff09; 全局向量的词嵌入&#xff08;Global Vectors for Word Representation&#xff09;&#xff0c;通常简称为GloVe&#xff0c;是一种用于将词语映射到连续向量空间的词嵌入方法。它旨在捕捉词语之间的语义关系和语法关系&#…

嵌入式Linux开发实操(十三):GPIO接口开发

从版本4.8开始,Linux内核引入了一个新的基于字符设备的用户空间API,用于管理和控制GPIO(通用输入/输出),在Linux内核4.8之前,在用户空间中管理GPIO的唯一接口是sysfs接口,pio通过/sys/class/gpio中的导出文件进行配置和控制,可以通过该接口执行的基本GPIO操作,比如: …

史上最全AP、mAP详解与代码实现

文章目录 前言一、mAP原理1、mAP概念2、准确率3、精确率4、召回率5、AP: Average Precision 二、mAP0.5与mAP0.5:0.951、mAP0.52、mAP0.5:0.95 三、mAP代码实现1、真实标签json文件格式2、模型预测标签json文件格式3、mAP代码实现4、mAP结果显示 四、模型集成mAP代码1、模型mai…

比较器的工作原理及性能指标介绍

一、什么是比较器 比较器的功能是比较两个或更多数据项&#xff0c;以确定它们是否相等&#xff0c;或者确定它们之间的大小关系和排列顺序&#xff0c;这称为比较。可以实现此比较功能的电路或设备称为比较器。比较器是将模拟电压信号与参考电压进行比较的电路。比较器的两个…

广播、组播

1.广播 向子网中多台计算机发送消息&#xff0c;并且子网中所有的计算机都可以接收到发送方发送的消息&#xff0c;每个广播消息都包含一个特殊的IP地址&#xff0c;这个IP中子网内主机标志部分的二进制全部为1。 a.只能在局域网中使用。 b.客户端需要绑定服务器广播使用的端口…

解读GIS软件:从ArcGIS到山海鲸可视化的全方位介绍

在现代社会&#xff0c;地理信息系统&#xff08;GIS&#xff09;的应用已经渗透到了各个领域&#xff0c;为我们提供了丰富的地理数据分析和可视化工具。下面介绍几款常见的GIS工具软件&#xff0c;一起来了解它们的特点和优势。 1. ArcGIS: ArcGIS由Esri公司开发&#xff0c;…

使用Spring Boot和Kafka实现消息订阅和发送

文章目录 一&#xff0c;新建Spring Boot1&#xff0c;Maven配置2&#xff0c;无法识别为SpringBoot项目3&#xff0c;无效的源发行版4&#xff0c;无法访问SpringApplication5&#xff0c;运行直接Finish6&#xff0c;服务运行成功 二&#xff0c;安装启动Kafka1&#xff0c;下…

20 MySQL(下)

文章目录 视图视图是什么定义视图查看视图删除视图视图的作用 事务事务的使用 索引查询索引创建索引删除索引聚集索引和非聚集索引影响 账户管理&#xff08;了解非DBA&#xff09;授予权限 与 账户的相关操作 MySQL的主从配置 视图 视图是什么 通俗的讲&#xff0c;视图就是…

uniapp -- 在组件中拿到pages.json下pages设置navigationBarTitleText这个值?

1:在 pages.json 文件中设置 navigationBarTitleText,例如: {"pages": [{"path": "pages/home/index","style": {"navigationBarTitleText": "首页",&

lodash 之 _.isEmpty

lodash.isEmpty() 是 Lodash 库中的一个函数&#xff0c;用于检查给定值是否为空。它可以用于判断对象、数组、字符串等不同类型的值是否为空。 const _ require(lodash);console.log(_.isEmpty(null)); // 输出: trueconsole.log(_.isEmpty(undefined)); // 输出: trueconso…

C++ 缺失的数字

有n个数字&#xff0c;值就是1~n&#xff0c;现发现丢失了2个数字&#xff0c;请你根据剩余的n-2个数字&#xff0c;编程计算一下&#xff0c;缺失的是哪两个数字呢&#xff1f; &#xff08;使用桶排&#xff0c;标记输入过的数字&#xff09; #include<bits/stdc.h> us…

Web开发模式、API接口、restful规范、序列化和反序列化、drf安装和快速使用、路由转换器(复习)

一 Web开发模式 1. 前后端混合开发模式 前后端混合开发模式是一种开发方式&#xff0c;将前端和后端的开发工作结合在一起&#xff0c;以加快项目的开发速度和 提高协作效率。这种模式通常用于快速原型开发、小型项目或敏捷开发中。在前后端混合开发模式中&#xff0c;前端和…

CATIA Composer R2023安装教程

软件下载 软件&#xff1a;CATIA Composer版本&#xff1a;2023语言&#xff1a;简体中文大小&#xff1a;1.82G安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.60GHz 内存8G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pa…

汇编-内中断

中断的意思是指, CPU不再接着(刚执行完的指令) 向下执行, 而是转去处理这个特殊信息。 内中断的产生 8086CPU,当CPU内部有下面的情况发生的时候, 将产生相应的中断信息: (1)除法错误, 比如, 执行div指令产生的除法溢出; (2)单步执行;   (3)执行into指令; (4)执…

使用python编写脚本测试目标主机的TCP端口连通性

使用Python的Socket模块的connect()函数来尝试连接目标主机的特定端口。如果连接成功&#xff0c;则说明该端口是打开的&#xff1b;否则&#xff0c;该端口是关闭的。 下面是一个示例脚本&#xff0c;可以检测目标IP的22端口是否开启&#xff1a; import socket def check_po…

文件上传漏洞-upload靶场3-4(全网最详细解读)

文件上传漏洞-upload靶场3-4关通关笔记&#xff08;全网最详细解读&#xff09; upload 第三关&#xff08;特殊后缀&#xff09; 思路 按照第一关和第二关的思路&#xff0c;先随便上传一个文件用burpsuite工具抓包&#xff0c;看它到底是前段验证还是后端验证。 上传一个we…

National Instruments NI-XNET

该接口增加了对National Instruments的NI-XNET CAN控制器的支持。 Note NI-XNET仅支持windows平台。 Bus class can.interfaces.nixnet.NiXNETcanBus class can.interfaces.nixnet.NiXNETcanBus( channel=CAN1, bitrate=500000, timing=None, can_filters

社招中级前端笔试面试题总结

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 typeof null 的结果是什么&#xff0c;为什么&#xff1f; typeof null 的结果是Object。 在 JavaScript 第一个版本中&#xff0c;所有值都存储在 32…

网络编程 day 3

1、UDP下载 #include<myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__); \perror(msg);\ }while(0)#define SER_PORT 8888 //端口号&#xff0c;范围1024~49151 #define SET_IP "192.168.114.85" //本机…

javaee spring 静态代理

静态代理 package com.test.staticProxy;public interface IUsersService {public void insert(); }package com.test.staticProxy;//目标类 public class UsersService implements IUsersService {Overridepublic void insert() {System.out.println("添加用户");…