utility_expected

utility_expected (std::expected - 예상 값 또는 예상치 못한 값 표현)

std::expected 클래스 템플릿은 두 값 중 하나를 나타내는 방법을 제공해요. T 타입의 예상 값(expected value) 또는 E 타입의 예상치 못한 값(unexpected value)을 저장할 수 있지요. expected 객체는 절대 값이 없는 상태가 아니며, 성공 또는 실패 결과를 명시적으로 다룰 때 유용해요.

이 페이지에서는 C++23부터 도입된 std::expected의 템플릿 매개변수, 중첩 타입, 멤버 함수, 비멤버 함수, 헬퍼 클래스 등을 자세히 설명할게요.

출처: cppreference

본문

<expected> 헤더에 정의되어 있어요.

정의
template < class T , class E > class expected ; (1) (since C++23)
template < class T , class E > requires std :: is_void_v < T > class expected < T , E > ; (2) (since C++23)

std::expected 클래스 템플릿은 두 값 중 하나를 나타내는 방법을 제공해요. T 타입의 예상 값 또는 E 타입의 예상치 못한 값이지요. expected는 절대 값이 없는 상태가 아니에요.

참조 타입, 함수 타입 또는 std::unexpected의 특수화로 expected를 인스턴스화하면 프로그램은 ill-formed예요. 또한 Tstd::in_place_tstd::unexpect_t가 아니어야 해요.

템플릿 매개변수

T - 예상 값의 타입이에요. (cv-qualified) void이거나 Destructible 요구 사항을 충족해야 해요. 특히 배열과 참조 타입은 허용되지 않아요.
E - 예상치 못한 값의 타입이에요. Destructible 요구 사항을 충족해야 하고, std::unexpected의 유효한 템플릿 인자여야 해요. 특히 배열, 비객체 타입, cv-qualified 타입은 허용되지 않아요.

중첩 타입

타입 정의
value_type T
error_type E
unexpected_type std::unexpected<E>

멤버 템플릿

템플릿 정의
rebind < U > std :: expected < U , error_type >

데이터 멤버

멤버 설명
bool has_val expected 객체가 현재 예상 값을 나타내는지 여부 (설명 전용 멤버 객체*)
T val (메인 템플릿만) 예상 값 (설명 전용 variant 멤버 객체*)
E unex 예상치 못한 값 (설명 전용 variant 멤버 객체*)

멤버 함수

(constructor) expected 객체를 생성해요 (공용 멤버 함수) [edit]
(destructor) expected 객체와 포함된 값을 소멸해요 (공용 멤버 함수) [edit]
operator= 내용을 할당해요 (공용 멤버 함수) [edit]
Observers
operator-> operator* 예상 값에 접근해요 (공용 멤버 함수) [edit]
operator bool has_value 객체가 예상 값을 포함하는지 확인해요 (공용 멤버 함수) [edit]
value 예상 값을 반환해요 (공용 멤버 함수) [edit]
error 예상치 못한 값을 반환해요 (공용 멤버 함수) [edit]
value_or 예상 값이 있으면 그 값을, 없으면 다른 값을 반환해요 (공용 멤버 함수) [edit]
error_or 예상치 못한 값이 있으면 그 값을, 없으면 다른 값을 반환해요 (공용 멤버 함수) [edit]
Monadic operations
and_then 예상 값이 있으면 주어진 함수를 적용한 결과를 반환하고, 없으면 expected 자신을 반환해요 (공용 멤버 함수) [edit]
transform 예상 값이 있으면 변환된 예상 값을 담은 expected를 반환하고, 없으면 expected 자신을 반환해요 (공용 멤버 함수) [edit]
or_else 예상 값이 있으면 expected 자신을 반환하고, 없으면 예상치 못한 값에 주어진 함수를 적용한 결과를 반환해요 (공용 멤버 함수) [edit]
transform_error 예상 값이 있으면 expected 자신을 반환하고, 없으면 변환된 예상치 못한 값을 담은 expected를 반환해요 (공용 멤버 함수) [edit]
Modifiers
emplace 예상 값을 제자리에서 생성해요 (공용 멤버 함수) [edit]
swap 내용을 교환해요 (공용 멤버 함수) [edit]

비멤버 함수

operator== (C++23) expected 객체를 비교해요 (함수 템플릿) [edit]
swap (std::expected) (C++23) std::swap 알고리즘을 특수화해요 (함수) [edit]

헬퍼 클래스

unexpected (C++23) 예상치 못한 값으로 표현돼요 (클래스 템플릿) [edit]
bad_expected_access (C++23) 예상치 못한 값을 포함하는 expected에 대한 확인된 접근을 나타내는 예외예요 (클래스 템플릿) [edit]
unexpect unexpect_t (C++23) expected의 예상치 못한 값에 대한 제자리 생성 태그예요 (태그) [edit]

참고 사항

같은 기능을 가진 타입은 Rust에서는 Result, Haskell에서는 Either라고 불러요.

Feature-test macro 표준 기능
__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 << "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

결함 보고서

다음 동작 변경 결함 보고서는 이전에 발표된 C++ 표준에 소급 적용되었어요.

DR 적용 대상 발표된 동작 올바른 동작
LWG 4141 C++23 저장 공간 할당 요구 사항이 혼란스러웠어요 포함된 객체는 expected 객체 안에 중첩되어야 해요

참고 문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 22.8 Expected objects [expected]

같이 보기

variant (C++17) 타입 안전한 구분 유니온 (클래스 템플릿) [edit]
optional (C++17) 객체를 보유할 수도 있고 보유하지 않을 수도 있는 래퍼 (클래스 템플릿) [edit]

더 알아보기 (Learn more)

cppreference