C++20을 사용한 단일 헤더 std::expected 구현입니다.
라이브러리는 다음 두 가지 제안을 구현합니다.
이 구현은 네임스페이스 rd에서 예상되는 것을 제공합니다. 따라서 std::expected를 사용하려면 rd::expected를 사용하세요.
std::expected는 오류 처리를 위한 메커니즘입니다. 이는 Rust의 std::result와 매우 유사합니다. std::expected는 기본적으로 Result 또는 Error 중 하나를 포함합니다.
예외를 "항상" 사용하지 않는 데에는 아마도 두 가지 이유가 있을 것입니다.
라이브러리를 작성하는 동안 오류 처리에 큰 문제가 발생합니다. 라이브러리에서 오류 조건에서 예외를 발생시키도록 선택하면 라이브러리 사용자를 위한 선택이 됩니다. 라이브러리의 오류 조건은 해당 라이브러리를 사용하는 애플리케이션의 컨텍스트에서 예외적인 상황일 수도 있고 그렇지 않을 수도 있습니다.
std::expected는 애플리케이션 컨텍스트에서 예외가 아닌 오류 조건에 사용할 수 있는 예외에 대한 표준 대안을 제공합니다.
이렇게 말하는 동안 공황 상태에는 예외가 유용하다는 점에 유의해야 합니다. 그리고 예외만 사용해야 하는 명백한 패닉 상태가 많이 있습니다.
error_code는 가장 간단한 오류 처리 메커니즘으로 사용되었습니다. 역사적으로 error_code는 단순한 정수이므로 풍부한 오류 컨텍스트에 적합하지 않습니다.
요즘에는 C++ 헤더 <system_error>가 더 풍부한 오류 코드를 제공합니다. 그러나 error_code는 반환 채널을 독점하게 만듭니다. 따라서 값은 다른 채널을 통해 출력되어야 합니다.
또한 각 함수 호출 후에 if 조건을 작성해야 합니다.
std::expected는 결코 비어 있지 않을 것임을 보장합니다. 즉, 어느 시점에서든 값 또는 오류 중 하나가 포함됩니다. 이렇게 하면 사용하기가 정말 쉽습니다.
auto get_file_handle (std::string_view path) -> rd::expected<file, fail_reason>;
auto read_file (file f) -> rd::expected<std::string, fail_reason>;
auto to_int (std::string str) -> rd::expected<int, fail_reason>;
auto increment ( int x) -> int;
auto read_int_with_increment (std::string_view path) -> rd::expected<int, fail_reason>{
return get_file_handle (path)
. and_then (read_file)
. and_then (to_int)
. transform (increment);
}
template < typename T, typename E>
class expected
T, E는 논문에서도 지원되지 않으므로 참조 유형이 될 수 없습니다.
using value_type = T;
using error_type = E;
using unexpected_type = unexpected<E>;
template < class U >
using rebind = expected<U, error_type>;
기본 생성자:
constexpr expected ();
복사 생성자:
constexpr expected (expected const &);
이동 생성자:
constexpr expected (expected &&);
예상 생성자:
U는 T로 변환 가능해야 하고, G는 E로 변환 가능해야 합니다.
template < class U , class G >
constexpr expected (expected<U, G> const &);
template < class U , class G >
constexpr expected (expected<U, G> &&);
값 생성자:
T(예상 값 부분)를 초기화하기 위해 값을 받아들이는 예상 <T , E>의 생성자입니다.
template < class U = T>
constexpr expected (U&& v);
예상치 못한 생성자:
E(예상 오류 부분)를 초기화하기 위해 rd::unexpected 인스턴스를 허용하는 Expect<T, E>의 생성자입니다.
template < class G >
constexpr expected (unexpected<G> const &);
template < class G >
constexpr expected (unexpected<G> &&);
in_place_t 생성자:
T를 초기화하기 위해 in_place 태그와 인수(전달될)를 허용하는 예상<T, E>의 생성자입니다.
template < class ... Args>
constexpr expected (std:: in_place_t , Args&&... args);
template < class U , class ... Args>
constexpr expected (std:: in_place_t , std::initializer_list<U>, Args&&... args);
unexpect_t 생성자:
E를 초기화하기 위해 rd::unexpect 태그와 인수(전달될)를 허용하는 Expect<T, E>의 생성자입니다.
template < class ... Args>
constexpr expected (rd:: unexpect_t , Args&&... args);
template < class G , class ... Args>
constexpr expected (rd:: unexpect_t , std::initializer_list<G>, Args&&... args);
복사 할당:
constexpr expected& operator =(expected const &);
이동 할당:
constexpr expected& operator =(expected &&);
값 할당:
예상되는 값을 할당합니다.
template < class U = T>
constexpr expected& operator =(U&& rhs);
rd::예기치 않은 할당:
예상되는 오류를 할당합니다.
template < class G >
constexpr expected& operator =(unexpected<G> const &);
template < class G >
constexpr expected& operator =(unexpected<G> &&);
장소:
예상되는 새 값을 생성하는 인수를 허용하고 이에 할당합니다.
template < class ... Args>
constexpr T& emplace (Args&&... args);
template < class U , class ... Args>
constexpr T& emplace (std::initializer_list<U>, Args&&...);
멤버 함수와 친구 함수 교환
// For accessing T's members
// precondition: has_value() == true
constexpr T const * operator ->() const noexcept ;
// precondition: has_value() == true
constexpr T* operator ->() noexcept ;
// Getting reference to T
// precondition: has_value() == true
constexpr T const & operator *() const & noexcept ;
// precondition: has_value() == true
constexpr T& operator *() & noexcept ;
// precondition: has_value() == true
constexpr T&& operator *() && noexcept ;
// precondition: has_value() == true
constexpr T const && operator *() const && noexcept ;
// Query if value exists
constexpr explicit operator bool () const noexcept ;
constexpr bool has_value () const noexcept ;
// Get value, if not exists throws exception rd::bad_expected_access(error())
constexpr T const & value () const &;
constexpr T& value () &;
constexpr T&& value() &&;
constexpr T const && value() const &&;
// Get error, (undefined behavior if error not exists)
constexpr E const & error () const &;
constexpr E& error () &;
constexpr E&& error() &&;
constexpr E const && error() const &&;
// Get the value, if value doesn't exist return v
template < class U >
constexpr T value_or (U&& v) const &;
template < class U >
constexpr T value_or (U&& v) &&;
그런 다음:
F는 예상 값 유형으로 호출할 수 있어야 하며 오류 유형이 E여야 하는 예상을 반환해야 합니다. 오류가 있는 경우 현재 예상 오류를 반환하고 다른 값은 f를 호출한 결과를 값으로 반환합니다.
template < class F >
constexpr auto and_then (F&& f) &;
template < class F >
constexpr auto and_then (F&& f) &&;
template < class F >
constexpr auto and_then (F&& f) const &;
template < class F >
constexpr auto and_then (F&& f) const &&;
or_else:
F는 예상 오류 유형으로 호출할 수 있어야 하며 값 유형이 T여야 하는 예상을 반환해야 합니다.
invoke_result_t<F, E>
가 예상(값 유형이 T와 동일해야 함)의 특수화인 경우, 값이 있으면 값은 F의 Invoke_result_t에 래핑되어 반환되고, 그렇지 않으면 f 호출 결과를 반환합니다.
invoke_result_t<F, E>
가 void이고 오류가 있으면 오류와 함께 F가 호출됩니다. 현재 예상이 결과로 반환됩니다.
template < class F >
constexpr auto or_else (F&& f) &;
template < class F >
constexpr auto or_else (F&& f) &&;
template < class F >
constexpr auto or_else (F&& f) const &;
template < class F >
constexpr auto or_else (F&& f) const &&;
변환:
F는 현재 예상되는 값 유형으로 호출 가능해야 합니다. 현재 예상에 오류가 포함된 경우 결과 예상에는 해당 오류가 포함되고 그렇지 않으면 F를 사용하여 현재 예상 값을 호출한 결과가 포함됩니다.
template < class F >
constexpr auto transform (F&& f) &;
template < class F >
constexpr auto transform (F&& f) &&;
template < class F >
constexpr auto transform (F&& f) const &;
template < class F >
constexpr auto transform (F&& f) const &&;
변환_오류:
F는 현재 예상되는 오류 유형으로 호출 가능해야 합니다. 현재 예상에 값이 포함된 경우 결과 예상에는 해당 값이 포함되고 그렇지 않으면 F를 사용하여 현재 예상 오류 호출 결과가 포함됩니다.
template < class F >
constexpr auto transform_error (F&& f) &;
template < class F >
constexpr auto transform_error (F&& f) &&;
template < class F >
constexpr auto transform_error (F&& f) const &;
template < class F >
constexpr auto transform_error (F&& f) const &&;
template < class U , class G >
constexpr friend bool operator ==(expected const &, expected<U, G> const &);
template < class U >
constexpr friend bool operator ==(expected const &, U const &);
template < class G >
constexpr friend bool operator ==(expected const &, rd::unexpected<G> const &);
template < typename T>
class unexpected
using value_type = T
복사 생성자:
constexpr unexpected (unexpected const &);
이동 생성자:
constexpr unexpected (unexpected&&);
in_place_t 생성자:
std::in_place 태그를 허용하고 args를 사용하여 T를 구성합니다.
template < typename ...Args>
constexpr unexpected (std:: in_place_t , Args&&... args);
template < typename U, typename ...Args>
constexpr unexpected (std:: in_place_t , std::initializer_list<U>, Args&&... args);
값 생성자:
오류가 있는 T를 구성합니다.
template < typename Err>
constexpr unexpected (Err&& err);
// value(): gets the stored T value
constexpr T & value () &;
constexpr T const & value () const &;
constexpr T && value() &&;
constexpr T const && value() const &&;
template < class E2 >
friend constexpr bool operator ==(unexpected const & x, unexpected< E2 > const & y);
bad_expected_access는 예외에서 파생됩니다. 오류 값을 저장합니다.
template < class E >
class bad_expected_access ;
E& error () & noexcept ;
E const & error () const & noexcept ;
E&& error() && noexcept ;
E const && error() const && noexcept ;
이는 예상되는 구성 오류를 나타내는 태그 유형일 뿐입니다.
라이브러리는 또한 rd::unexpect_t 유형의 예상치 못한 변수를 노출합니다.
inline constexpr unexpect_t unexpect{};