跳转至

expected

类模板 std::expected 提供存储二个值之一的方式。 std::expected 的对象再任何给定时刻要么保有一个期待的T 类型值,要么保有一个不期待的 E 类型值。 std::expected 决不会无值。

1 定义

template< class T, class E > 
class expected;
  • T: 期待的值的类型。类型必须为(可有 cv 限定的) void 或符合可析构 (Destructible) 要求(尤其是不允许数组或引用类型)。
  • E:不期待的值的类型。类型必须符合可析构 (Destructible) 要求,且必须对于 std::unexpected 为合法的模板形参(尤其是不允许数组、非对象类型及 cv 限定的类型)。

2 示例

#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';
            // If num did not have a value, dereferencing num
            // would cause an undefined behavior, and
            // num.value() would throw std::bad_expected_access.
            // num.value_or(123) uses specified default value 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"; // or invoke 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