C++ 中的 std::expected 是什么?

What is std::expected in C++?

在最受尊敬的 Whosebug 回答之一中,我找到了 std::expected 模板 class 用法的示例:

同时,我在 cppreference.com 上找不到任何提及此 class 的内容。你能解释一下它是什么吗?

实际上,了解 std::expected 的最佳方式是著名的 Andrei Alexandrescu 的有趣演讲:"Expect the Expected!"

它是什么以及何时使用

以下是 std::expected<T, E> 的三个补充解释:

  • 它是一个 return 类型的函数,它应该是 return 一个 T 值 - 但它可能会遇到一些错误,在这种情况下它将 return 该错误的描述符,类型为 E.

    一个例子:

    std::expected<ParsedData, ParsingError> parse_input(Input input);
    
  • 这是一种错误处理机制,是抛出异常的替代方法(在这种情况下,您总是 return 您应该的值),并且 returning status/error 代码(在这种情况下,您永远不会 return 您想要的值,并且必须使用输出参数)。

    以下是应用于上一个示例中的函数的两种备选错误处理机制:

    ParsedData    parse_input_2(Input input) noexcept(false);
    ParsingError  parse_input_3(ParsedData& result, Input input);
    
  • 它是 TE 类型的区分联合,使用一些方便的方法。

“它比 std::variant<T,E> 好在哪里?”

它的行为有点像 std::optional<T>,将重点放在预期的而不是意外的情况上:

  • result.has_value() - 如果我们得到一个值而不是错误,则为真。
  • if (result) - 检查相同的东西
  • *result - 如果存在 T 值,则为我们提供未定义的行为(与 std::optional 相同,尽管很多人不喜欢这样)。
  • result.value(),给我们 T 值(如果存在),否则抛出。

实际上,如果出现错误,最后一种访问模式的行为与 std::optional 不同:它抛出的是 bad_expected_access<E>,带有 returned 错误。这种行为可以被认为是一种从基于预期的错误处理切换到基于异常的错误处理的方式。

“嘿,我在标准中找过,但没有!”

std::expected 将成为即将发布的 C++23 标准的一部分。 proposal (P0323) 最近被接受了。

这就是说 - 它已经非常有用了,因为它不需要新的语言工具。我会推荐 Sy Brand (tartanllama) 的 implementation,它可以与 C++11 或更高版本一起使用。它还具有一些简洁的函数式扩展(可能未标准化)。