std::expected
来自cppreference.com
<tbody>
</tbody>
| 在标头 <expected> 定义
|
||
template< class T, class E > class expected; |
(1) | (C++23 起) |
template< class T, class E > requires std::is_void_v<T> class expected<T, E>; |
(2) | (C++23 起) |
类模板 std::expected 提供表示两个值之一的方式:它要么表示一个 T 类型的预期 值,要么表示一个 E 类型的非预期 值。expected 决不会无值。
2)
void 部分特化。表示一个 void 类型的预期值或在自身的存储中包含非预期值。如果包含非预期值,那么该值内嵌于 expected 对象。如果程序以引用类型、函数类型,或 std::unexpected 的特化实例化 expected,那么程序非良构。另外,T 必须不是 std::in_place_t 或 std::unexpect_t。
模板形参
| T | - | 预期值的类型。类型必须是(可有 cv 限定的)void,或者符合可析构 (Destructible) 要求(尤其是不允许数组或引用类型)。
|
| E | - | 非预期值的类型。类型必须符合可析构 (Destructible) 要求,且必须对于 std::unexpected 为合法的模板实参(尤其是不允许数组、非对象类型及 cv 限定的类型)。 |
嵌套类型
| 类型 | 定义 |
value_type
|
T
|
error_type
|
E
|
unexpected_type
|
std::unexpected<E>
|
成员模板
| 模板 | 定义 |
rebind<U>
|
std::expected<U, error_type>
|
数据成员
| 成员 | 描述 |
bool has_val
|
expected 对象当前是否表示预期值(仅用于阐述的成员对象*) |
T val (仅限主模板)
|
预期值 (仅用于阐述的变体成员对象*) |
E unex
|
非预期值 (仅用于阐述的变体成员对象*) |
成员函数
构造 expected 对象 (公开成员函数) | |
销毁 expected 对象以及其所含的值 (公开成员函数) | |
| 赋值内容 (公开成员函数) | |
观察器 | |
| 访问预期值 (公开成员函数) | |
| 检查对象是否含有预期值 (公开成员函数) | |
| 返回预期值 (公开成员函数) | |
| 返回非预期值 (公开成员函数) | |
| 如果有预期值则返回它,否则返回另一个值 (公开成员函数) | |
| 如果有非预期值则返回它,否则返回另一个值 (公开成员函数) | |
单子操作 | |
若存在预期值则返回给定的函数在其上的结果,否则返回 expected 本身 (公开成员函数) | |
若存在预期值则返回含有变换后的预期值的 expected,否则返回 expected 本身 (公开成员函数) | |
若 expected 含有预期值则返回其自身,否则返回给定的函数在非预期值上的结果 (公开成员函数) | |
若含有预期值则返回 expected 本身,否则返回含有变换后非预期值的 expected (公开成员函数) | |
修改器 | |
| 原位构造预期值 (公开成员函数) | |
| 交换内容 (公开成员函数) | |
非成员函数
(C++23) |
比较 expected 对象 (函数模板) |
(C++23) |
特化 std::swap 算法 (函数) |
辅助类
(C++23) |
表示一个非预期值 (类模板) |
(C++23) |
指示对含有非预期值的 expected 的有检查访问的异常 (类模板) |
(C++23) |
expected 中非预期值的原位构造标签 (类) (常量) |
注解
拥有相同功能的类型在 Rust 与 Haskell 中分别被称为 Result 和 Either。
| 功能特性测试宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__cpp_lib_expected |
202202L |
(C++23) | 类模板 std::expected 和关联的辅助类
|
202211L |
(C++23) | 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 << "值: " << *num << '\n';
// 如果 num 没有值,那么解引用 num 会造成未定义行为,而
// num.value() 会抛出 std::bad_expected_access。
// num.value_or(123) 则使用指定的默认值 123。
else if (num.error() == parse_error::invalid_input)
std::cout << "错误:无效输入\n";
else if (num.error() == parse_error::overflow)
std::cout << "错误:溢出\n";
else
std::cout << "非预期!\n"; // 或调用 std::unreachable();
};
for (auto src : {"42", "42abc", "meow", "inf"})
process(src);
}
输出:
str: "42", 值: 42
str: "42abc", 值: 42
str: "meow", 错误:无效输入
str: "inf", 错误:溢出
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
| 缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
|---|---|---|---|
| LWG 4141 | C++23 | 对存储分配的要求难以理解 | 包含的对象必须内嵌于 expected 对象
|
引用
- C++23 标准(ISO/IEC 14882:2024):
- 22.8 Expected objects [expected]
参阅
(C++17) |
类型安全的可辨识联合体 (类模板) |
(C++17) |
可能或可能不保有一个对象的包装器 (类模板) |