std::expected

来自cppreference.com
< cpp‎ | utility
 
 
 
 
在标头 <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 决不会无值。

1) 主模板。在自身的存储中包含预期值或非预期值,该值内嵌于 expected 对象。
2) void 部分特化。表示一个 void 类型的预期值或在自身的存储中包含非预期值。如果包含非预期值,那么该值内嵌于 expected 对象。

如果程序以引用类型、函数类型,或 std::unexpected 的特化实例化 expected,那么程序非良构。另外,T 必须不是 std::in_place_tstd::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
(公开成员函数) [编辑]
修改器
原位构造预期值
(公开成员函数) [编辑]
交换内容
(公开成员函数) [编辑]

[编辑] 非成员函数

比较 expected 对象
(函数模板) [编辑]
特化 std::swap 算法
(函数) [编辑]

[编辑] 辅助类

表示一个非预期值
(类模板) [编辑]
指示对含有非预期值的 expected 的有检查访问的异常
(类模板) [编辑]
expected 中非预期值的原位构造标签
(类) (常量) [编辑]

[编辑] 注解

拥有相同功能的类型在 Rust 与 Haskell 中分别被称为 ResultEither

功能特性测试 标准 功能特性
__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)
可能或可能不保有一个对象的包装器
(类模板) [编辑]