Namespaces
Variants

std:: expected

From cppreference.net
Utilities library
定义于头文件 <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 对象内部。

若程序实例化 expected 时使用引用类型、函数类型或 std::unexpected 的特化,则该程序非良构。此外, 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 对象
(函数模板)
特化 std::swap 算法
(函数)

辅助类

(C++23)
表示意外值的包装器
(类模板)
指示对包含意外值的 expected 进行受检访问时抛出的异常
(类模板)
用于在 expected 中原位构造意外值的标签
(标签)

注释

具有相同功能的类型在 Rust 中称为 Result ,在 Haskell 中称为 Either

功能测试 标准 功能
__cpp_lib_expected 202202L (C++23) 类模板 std::expected 及相关的 辅助类
202211L (C++23) std::expected 的 Monadic 函数

示例

#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 << "value: " << *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 << "error: invalid input\n";
        else if (num.error() == parse_error::overflow)
            std::cout << "error: overflow\n";
        else
            std::cout << "unexpected!\n"; // 或调用 std::unreachable();
    };
    for (auto src : {"42", "42abc", "meow", "inf"})
        process(src);
}

输出:

str: "42", value: 42
str: "42abc", value: 42
str: "meow", error: invalid input
str: "inf", error: overflow

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 应用于 发布时行为 正确行为
LWG 4141 C++23 存储分配的要求表述不清 所含对象必须嵌套在
expected 对象内部

参考文献

  • C++23 标准 (ISO/IEC 14882:2024):
  • 22.8 Expected 对象 [expected]

参见

(C++17)
类型安全的可辨识联合体
(类模板)
(C++17)
可能持有或未持有对象的包装器
(类模板)