0

0

如何在c++项目中使用std::expected进行错误处理传递? (组合与and_then)

穿越時空

穿越時空

发布时间:2026-01-10 13:35:27

|

483人浏览过

|

来源于php中文网

原创

std::expected 的 and_then 用于成功路径的链式组合,只在有值时调用并自动解包返回 expected,错误类型必须一致,不处理异常,需显式返回 unexpected;map 用于无错误转换,or_else 用于错误恢复。

如何在c++项目中使用std::expected进行错误处理传递? (组合与and_then)

std::expected 的基本组合:operator>> 和链式调用

std::expected 没有内置的 operator>>,但你可以用 and_then(C++23)实现类似 Result 类型的扁平化组合。它只在当前 expected 包含值(即 has_value() == true)时才调用传入的可调用对象,并自动解包返回值——前提是该可调用对象也返回 std::expected

常见错误是误以为 and_then 会处理错误分支;它完全忽略错误,只对成功路径做变换。若上游失败,整个链直接短路,保留原始错误。

  • and_then 接收一个参数为 T(即 expected::value_type)的函数,返回 std::expected
  • 返回类型中的错误类型 E 必须与原 expected 一致,否则编译失败
  • 不能用 and_thenint 转成 std::expected<:string std::error_code> 再转成 std::expected —— 错误类型不匹配
std::expected parse_int(std::string s) {
    try { return std::stoi(s); }
    catch (...) { return std::unexpected("invalid number"); }
}

std::expected to_double(int x) { return static_cast(x) * 1.5; }

auto result = parse_int("42").and_then(to_double); // result 是 std::expected,值为 63.0

and_then 中如何处理可能失败的中间步骤?

如果中间函数本身也可能失败(即返回 std::expected),and_then 正好适配这种“一环扣一环”的错误传递场景。它天然支持嵌套失败:只要任意一环返回 std::unexpected,后续不会执行,最终结果携带该环节的错误。

容易踩的坑是试图在 and_then 回调里 throw 异常——这会导致程序终止(除非你显式捕获并转为 std::unexpected)。标准要求 and_then 内部不传播异常。

立即学习C++免费学习笔记(深入)”;

Sider
Sider

多功能AI浏览器助手,帮助用户进行聊天、写作、阅读、翻译等

下载
  • 所有中间逻辑必须显式返回 std::expected,不能靠异常退出
  • 若需 fallback 行为(比如“解析失败就用默认值”),应在外层用 value_oror_else,而非塞进 and_then
  • and_then 不改变错误类型,所以多个步骤共用同一错误类型(如 std::string 或枚举)会更易维护
std::expected read_file(std::string path) {
    std::ifstream f(path);
    if (!f.is_open()) return std::unexpected("file not found");
    return std::string{std::istreambuf_iterator(f), {}};
}

std::expected count_lines(std::string content) { size_t n = 0; for (char c : content) if (c == '\n') ++n; return n; }

// 组合:read → count,任一失败则终止,错误类型保持 std::string auto lines = read_file("data.txt").and_then(count_lines);

和 map、or_else 配合使用的边界情况

and_then 只负责“成功后继续返回 expected”的场景;若你想对值做纯转换(不引入新错误),用 map 更轻量;若想处理错误分支,得靠 or_else。三者分工明确,混用时要注意语义断裂点。

典型误用:用 map 去调用一个可能抛异常的函数,导致未定义行为;或在 or_else 里返回了和原 expected 错误类型不同的类型,引发编译错误

  • map(f)f 接收 T,返回 U(非 expected),整个结果仍是 expected
  • or_else(f)f 接收 const E&,返回 std::expected,用于错误恢复
  • 三者返回类型都要求错误类型 E 严格一致,C++23 标准不支持自动转换
std::expected get_id() { return 123; }

// map:安全转换,无新错误 auto str_id = getid().map([](int i) { return "ID" + std::to_string(i); });

// or_else:错误时尝试 fallback auto fallback = get_id() .or_else([](const std::string& e) -> std::expected { if (e == "not ready") return 0; return std::unexpected(e); });

实际项目中 and_then 的性能与兼容性提醒

and_then 是零开销抽象:它只是条件调用加移动语义,没有动态分配,也没有虚函数。但它的可用性依赖 C++23 标准库实现。GCC 13+、Clang 16+、MSVC 19.35+ 支持,旧版本需用第三方库(如 TartanLlama/expected)并注意 API 差异(比如有些叫 bind 而非 and_then)。

真正容易被忽略的是错误类型的生命周期管理。如果你用 std::string 作错误,频繁构造临时字符串会影响性能;更稳妥的做法是定义轻量错误枚举,或用 std::error_code 配合自定义 std::error_category

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

520

2023.09.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

253

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

206

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1463

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

614

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

548

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

543

2024.04.29

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

25

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 3.6万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号