(C++23) expected 基础使用

news2024/12/27 18:00:52

文章目录

  • ⭐前言
  • ⭐expected
    • 🎛️基础使用
    • 🎛️单子操作 (Monadic operations)
      • 🎚️and_then & or_else
      • 🎚️transform & transform_error
  • ⭐END
    • 🌟跋
    • 🌟交流方式

⭐前言

在 C++17 中,提出了 optional 的可选项类型。但是该类型仅能表示二元状态,true | false 但在实际业务常见成功与否可以只用一个flag表示,但失败的原因却多种多样,需要以一种更丰富的形式表示。

因此在 C++23 中正式规范了std::expected,操作方式与原先的std::optional相似,又扩展了一些统一的处理方案。

同时这些方法在 C++23 中也为 std::optional 提供。

⭐expected

下面以一个获取星期几的字符串的demo为例子来表示。

🎛️基础使用

操作以使用 std::optional 一致,但这里多了一项 error 的选项。

#include <ctime>
#include <expected>
#include <iostream>
#include <string>
#include <typeinfo>

enum struct ParseError : int {
    Below,  // (<0)
    Above   // (>6)
};

std::expected<std::string, ParseError> get_weekDay(int d) {
    if (d < 0) {
        return std::unexpected(ParseError::Below);
    } else if (d > 6) {
        return std::unexpected(ParseError::Above);
    }

    // C++20 指定初始化
    std::tm t{.tm_wday = d};
    char    buffer[16];
    std::strftime(buffer, sizeof(buffer), "%A", &t);

    return std::string(buffer);
}

void test(int d) {
    auto ex = get_weekDay(d);
    if (ex.has_value()) {
        std::cout << ex.value() << std::endl;
    } else {
        if (ex.error() == ParseError::Below) {
            std::cout << "ParseError::Below" << std::endl;
        } else if (ex.error() == ParseError::Above) {
            std::cout << "ParseError::Above" << std::endl;
        } else {
            std::cout << ex.value_or("ParseError") << std::endl;
        }
    }
}

int main() {
    test(-1);
    test(0);
    test(114514);
}

🎛️单子操作 (Monadic operations)

下面仅对上面 demo 的 void test(int) 函数进行修改

一般来说 Monadic operations 会被翻译成一元操作,或者单目操作。不知道为什么std::expected - cppreference.com 这里翻译成单子操作。

🎚️and_then & or_else

and_then() 如果 *this:

  • 表示预期值,那么调用 f 并返回它的结果。

  • 否则返回一个包含非预期值的 std::expected 对象,以 *this 的非预期值初始化该值。

or_else 如果 *this:

  • 包含非预期值,那么以 *this 的非预期值作为实参调用 f 并返回它的结果。

  • 否则返回一个表示预期值的 std::expected 对象。

因此两者的使用非常灵活,使用得当可以非常遍历的进行链式编程。

这个写法让我回想起以前写 javascript 的时候。

void test(int d) {
    auto ex = get_weekDay(d);

    ex
        /**
         * 若存在预期值则返回给定的函数在其上的结果,否则返回 expected 本身
         */
        .and_then([](const auto& e) -> std::expected<std::string, ParseError> {
            std::cout << "[and_then] Type:" << typeid(e).name() << std::endl;
            std::cout << e << std::endl;
            return {e};
        })
        /**
         * 若 expected 含有预期值则返回其自身,否则返回给定的函数在非预期值上的结果
         */
        .or_else([](const auto& e) -> std::expected<std::string, ParseError> {
            std::cout << "[or_else] Type:" << typeid(e).name() << std::endl;

            if (e == ParseError::Below) {
                std::cout << "ParseError::Below" << std::endl;
            } else if (e == ParseError::Above) {
                std::cout << "ParseError::Above" << std::endl;
            } else {
                std::cout << "ParseError" << std::endl;
            }
            return std::unexpected{e};
        });
}

mingw-gcc 运行效果

[or_else] Type:10ParseError
ParseError::Below
[and_then] Type:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Sunday
[or_else] Type:10ParseError
ParseError::Above

🎚️transform & transform_error

transform() 如果 *this:

  • 表示预期值,那么调用 f 并返回一个包含预期值的 std::expected 对象,以 f 的结果初始化该值(或在结果类型是 void 时值初始化)。
  • 否则返回一个包含非预期值的 std::expected 对象,以 *this 的非预期值初始化该值。

transform_error() 如果 *this:

  • 包含非预期值,那么以 *this 的非预期值作为实参调用 f 并返回一个包含预期值的 std::expected 对象,以 f 的结果初始化该值。
  • 否则返回一个表示预期值的 std::expected 对象。

这两个基本可以被and_then & or_else取代。

主要区别在于,在成功调用时能保证返回一个std::expected,且依赖于 f 的返回值。

这是少有的在 C++ 中可以天然的允许链式编程的函数。

void test(int d) {
    auto ex = get_weekDay(d);

    ex
        /**
         * 若存在预期值则返回含有变换后的预期值的 expected,否则返回 expected 本身
         */
        .transform([](const auto& e) -> std::expected<std::string, ParseError> {
            std::cout << "[transform] Type:" << typeid(e).name() << std::endl;
            std::cout << e << std::endl;
            return {e};
        })
        /**
         * 若含有预期值则返回 expected 本身,否则返回含有变换后非预期值的 expected
         */
        .transform_error([](const auto& e) -> std::expected<std::string, ParseError> {
            std::cout << "[transform_error] Type:" << typeid(e).name() << std::endl;

            if (e == ParseError::Below) {
                std::cout << "ParseError::Below" << std::endl;
            } else if (e == ParseError::Above) {
                std::cout << "ParseError::Above" << std::endl;
            } else {
                std::cout << "ParseError" << std::endl;
            }
            return std::unexpected{e};
        });
}

mingw-gcc 运行效果

[transform_error] Type:10ParseError
ParseError::Below
[transform] Type:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Sunday
[transform_error] Type:10ParseError
ParseError::Above

⭐END

最后,如果像更深刻的体会这里的链式效果,建议将上面代码的 and_then & or_else 以相反的顺序调用一遍,会有不一样的效果。

这样可以帮助更好的理解调用的逻辑和设计出更好的代码。

🌟跋

ref:

标准库标头 expected

相关类型:

  • (C++17) any的使用与简单实现
  • (C++17) optional的使用
  • (C++17) variant的使用与union对比
  • (C++17) optional 的 3 种用法

🌟交流方式

⭐交流方式⭐ |C/C++|算法|设计模式|软件架构-CSDN社区

关注我,学习更多C/C++,python,算法,软件工程,计算机知识

B站:

👨‍💻主页:天赐细莲 bilibili

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

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

相关文章

量化交易backtrader实践(二)_基础加强篇(4)_交易设置与自定义绘图

这一节我们来深入实践交易的设置以及自定义绘图。 01_交易设置 参考文档&#xff1a; Backtrader系列教程④&#xff1a;交易篇&#xff08;上&#xff09;_backtrader撤单操作-CSDN博客量化投资之工具篇一&#xff1a;Backtrader从入门到精通&#xff08;8&#xff09;-交易…

记软件开发者画图(UML),使用WPS应用制图

目录 前言 一、什么是UML 二、使用什么画图工具 三、示例 ​四、IntelliJ IDEA 2021快速生成UML图 前言 做软件开发的从写第一个示例程序到最后写项目程序避不开的需要设计画图&#xff0c;所以今天我们就来梳理一下‌UML&#xff08;统一建模语言&#xff09;图形需要画…

《深度学习》卷积神经网络CNN 原理及其流程解析

目录 一、CNN图像原理 1、了解图像的原理 2、举例 二、CNN图像识别 1、画面不变性 2、主要表现 1&#xff09;平移不变性 2&#xff09;尺度不变性 3&#xff09;旋转不变性 3、传统神经网络识别 1&#xff09;数据预处理 2&#xff09;特征提取 3&#xff09;搭建神经网…

C++基础(8.继承_多态)

目录 继承&#xff1a; 继承的概念&#xff1a; 继承的定义&#xff1a; 基类和派生类对象赋值转换 &#xff1a; 继承中的作用域&#xff1a; 派生类的默认成员函数&#xff1a; 例题&#xff1a; ​编辑​编辑​编辑 继承与友元&#xff1a; 继承与静态成员&#xff1…

图片马赛克处理(Java)

1.需求 给图片的指定区域打码给整张图片打码马赛克方格取色支持中心点取色和随机取色马赛克支持灰度处理 2.源码 package com.visy.utils;import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOE…

Rabbitmq消息队列,安装,使用,三种工作模式

产品 消息队列技术介绍 消息队列概述 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合、异步消息、流量削锋等问题。实现高性能、高可用、可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。 目前在生产环境&#xff0c;使用较多的消息队列有…

基于51单片机的汽车倒车防撞报警器系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 本课题基于微控制器控制器&#xff0c; 设计一款汽车倒车防撞报警器系统。 要求&#xff1a; 要求&#xff1a;1.配有距离&#xff0c; 用于把车和障碍物之间的距离信号送入控制器。 2.配有报警系…

2024AI做PPT软件如何重塑演示文稿的创作

现在AI技术的发展已经可以帮我们写作、绘画&#xff0c;最近我发现了不少ai做ppt的工具&#xff01;不体验不知道&#xff0c;原来合理使用AI工具可以有效的帮我们进行一些办公文件的编写&#xff0c;提高了不少工作效率。如果你也有这方面的需求就接着往下看吧。 1.笔灵AIPPT…

内网穿透out了?黑群晖+IPv6+NAS公网助手的访问体验

科技宅最带折腾黑群晖&#xff0c;这不&#xff0c;尝试一下ipv6动态域名解析&#xff0c;远程访问群晖NAS的方法千千万&#xff0c;这个方法我早就想到了&#xff0c;今天终于体验了一把&#xff0c;把经验分享一下&#xff1a; 目录 黑群晖的魅力 IPv6的加入&#xff1a;无…

Python办公自动化教程(003):PDF的加密

【1】代码 from PyPDF2 import PdfReader, PdfWriter# 读取PDF文件 pdf_reader PdfReader(./file/Python教程_1.pdf) pdf_writer PdfWriter()# 对第1页进行加密 page pdf_reader.pages[0]pdf_writer.add_page(page) # 设置密码 pdf_writer.encrypt(3535)with open(./file/P…

上位机图像处理和嵌入式模块部署(linux小系统开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 和若干年前相比较&#xff0c;现在嵌入式linux开发要简单得多。稍微贵一点的有树莓派&#xff0c;国产的有各种水果派&#xff0c;基本上都可以按照…

苍穹外卖学习日志 -----20天项目从零到完结-----含软件下载,环境配置,框架学习,代码编写,报错处理,测试联调,每日总结,心路历程等等......

年份 2024 基础&#xff1a;Javase Javaweb 已完结 2024 8.25---9.14 20天 Day-01 8.25 今天开始学习已经晚了&#xff0c;网盘下载了一下文件&#xff0c;做了一些开始项目的准备工作。 本来其实打算用notepad来写学习日志的&#xff0c;但是那个传…

如何给bat文件替换好看的图标

最近遇到软件运行在Windows系统&#xff0c;通过bat文件启动&#xff0c;但是bat文件的图标不好看&#xff0c;而且作为启动快捷方式放桌面看上去跟其他软件不搭调&#xff0c;于是得给bat文件换个软件图标。 软件ico图标 Windows系统下使用.ico文件作为软件图标。另外favicon…

go libreoffice word 转pdf

一、main.go 关键代码 完整代码 package mainimport ("fmt""github.com/jmoiron/sqlx""github.com/tealeg/xlsx""log""os/exec""path/filepath" ) import _ "github.com/go-sql-driver/mysql"import &q…

Python练习宝典:Day 1 - 选择题 - 基础知识

目录 一、踏上Python之旅二、Python语言基础三、流程控制语句四、序列的应用 一、踏上Python之旅 1.想要输出 I Love Python,应该使用()函数。 A.printf() B.print() C.println() D.Print()2.Python安装成功的标志是在控制台(终端)输入python/python3后,命令提示符变为: A.&…

数业智能心大陆:职场倦怠的新解法

什么是职业倦怠&#xff1f; 在职场中&#xff0c;职业倦怠的表现形式丰富多样。从数业智能心大陆 AI 心理咨询平台的数据来看&#xff0c;职业倦怠呈现出多种状态。教师可能对教学不再满怀热情&#xff0c;精心备课也成为过去式&#xff1b;情绪上容易烦躁、易怒&#xff0c;在…

【d47_2】【Java】【力扣】1791.找出星型图的中心节点

思路 直接判断 edges[0][0] edges[0][1] edges[1][0] edges[1][1] 谁重复了 例如&#xff1a; [ [1,2] [2,3] ....],那么中心节点一定是2 代码 class Solution {public int findCenter(int[][] edges) {for (int i0;i<1;i){if (edges[1][0]edges[0][i]) {return edg…

车载软件调试工具系列---Trace32简介UI界面简介

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

java项目之常规应急物资管理系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的常规应急物资管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息。 项目简介&#xff1a; 基于SpringBootVue的…

TikTok流量不佳:是网络环境选择不当还是其他原因?

TikTok&#xff0c;作为全球短视频社交平台的佼佼者&#xff0c;每天都有海量的内容被上传和分享。然而&#xff0c;很多用户和内容创作者发现&#xff0c;他们的TikTok视频流量并不理想。这引发了一个问题&#xff1a;TikTok流量不佳&#xff0c;是因为网络环境选择不当&#…