讲师中心 微信公众号
AI工具推荐 视频效率加速

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

夏墨君_8425

夏墨君_8425

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

|

503人浏览过

|

来源于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<t e>::value_type</t>)的函数,返回 std::expected<u e></u>
  • 返回类型中的错误类型 E 必须与原 expected 一致,否则编译失败
  • 不能用 and_then 把 int 转成 std::expected<:string std::error_code></:string> 再转成 std::expected<double std::string></double> —— 错误类型不匹配
std::expected<int, std::string> parse_int(std::string s) {
    try { return std::stoi(s); }
    catch (...) { return std::unexpected("invalid number"); }
}
<p>std::expected<double, std::string> to_double(int x) {
return static_cast<double>(x) * 1.5;
}</p><p>auto result = parse_int("42").and_then(to_double);
// result 是 std::expected<double, std::string>,值为 63.0</p>

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

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

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

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

C++ 算法竞赛自动化测试数据生成与校验框架
C++ 算法竞赛自动化测试数据生成与校验框架

根据原题生成新题面、验证器及完整测试数据,自动套用 testlib 模板,用于用户要求生成测试数据时。

下载
  • 所有中间逻辑必须显式返回 std::expected,不能靠异常退出
  • 若需 fallback 行为(比如“解析失败就用默认值”),应在外层用 value_or 或 or_else,而非塞进 and_then
  • and_then 不改变错误类型,所以多个步骤共用同一错误类型(如 std::string 或枚举)会更易维护
std::expected<std::string, std::string> 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<char>(f), {}};
}
<p>std::expected<size_t, std::string> count_lines(std::string content) {
size_t n = 0;
for (char c : content) if (c == '\n') ++n;
return n;
}</p><p>// 组合:read → count,任一失败则终止,错误类型保持 std::string
auto lines = read_file("data.txt").and_then(count_lines);</p>

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

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

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

  • map(f):f 接收 T,返回 U(非 expected),整个结果仍是 expected<u e></u>
  • or_else(f):f 接收 const E&,返回 std::expected<t e></t>,用于错误恢复
  • 三者返回类型都要求错误类型 E 严格一致,C++23 标准不支持自动转换
std::expected<int, std::string> get_id() { return 123; }
<p>// map:安全转换,无新错误
auto str_id = get<em>id().map([](int i) { return "ID</em>" + std::to_string(i); });</p><p>// or_else:错误时尝试 fallback
auto fallback = get_id()
.or_else([](const std::string& e) -> std::expected<int, std::string> {
if (e == "not ready") return 0;
return std::unexpected(e);
});</p>

实际项目中 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。

热门AI工具

更多
Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

相关专题

更多
string转int
string转int

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

5259

2023.08.02

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

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

1938

2023.09.20

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

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

1558

2023.08.03

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

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

2244

2023.09.04

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

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

5784

2023.10.24

字符串介绍
字符串介绍

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

4869

2023.11.24

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

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

6594

2024.03.22

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

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

8874

2024.04.29

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

60

2026.09.23

热门下载

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

精品课程

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn