ส่วนหัวเดียว std::คาดว่าจะมีการใช้งานโดยใช้ C ++ 20
ห้องสมุดดำเนินการตามข้อเสนอ 2 ข้อนี้:
การใช้งานนี้จัดเตรียมไว้ในเนมสเปซ rd ดังนั้นสำหรับการใช้งาน std::expected ให้ใช้ rd::expected
std::expected เป็นกลไกสำหรับการจัดการข้อผิดพลาด สิ่งนี้คล้ายกับ std::result ของสนิมมาก std::expected โดยทั่วไปจะมีผลลัพธ์หรือข้อผิดพลาดอย่างใดอย่างหนึ่ง
อาจมี 2 เหตุผลที่ไม่ใช้ข้อยกเว้น "เสมอ":
ในขณะที่เขียนไลบรารี่ใดๆ สิ่งนี้ทำให้เกิดปัญหาใหญ่ในการจัดการข้อผิดพลาด ในห้องสมุด ถ้าเราเลือกที่จะโยนข้อยกเว้นตามเงื่อนไขข้อผิดพลาด เรากำลังทำการเลือกสำหรับผู้ใช้ห้องสมุด เงื่อนไขข้อผิดพลาดในไลบรารีสามารถหรือไม่สามารถเป็นสถานการณ์พิเศษในบริบทของแอปพลิเคชันที่ใช้ไลบรารีนั้นได้
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 , E> ที่ยอมรับค่าเพื่อเริ่มต้น T(ส่วนของค่าที่คาดหวัง)
template < class U = T>
constexpr expected (U&& v);
ตัวสร้างที่ไม่คาดคิด:
ตัวสร้างสำหรับคาดหวัง <T, E> ที่ยอมรับอินสแตนซ์ rd::unexpected เพื่อเริ่มต้น E (ส่วนข้อผิดพลาดของที่คาดหวัง)
template < class G >
constexpr expected (unexpected<G> const &);
template < class G >
constexpr expected (unexpected<G> &&);
ตัวสร้าง in_place_t:
ตัวสร้างสำหรับ <T, E> ที่คาดหวังที่ยอมรับแท็ก in_place และอาร์กิวเมนต์ (ที่จะส่งต่อ) เพื่อเริ่มต้น T
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:
ตัวสร้างสำหรับ <T, E> ที่คาดหวังที่ยอมรับแท็ก rd::unexpect และอาร์กิวเมนต์ (ที่จะส่งต่อ) เพื่อเริ่มต้น 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> &&);
วาง:
ยอมรับ args ให้กับตัวสร้างค่าใหม่ตามที่คาดไว้และกำหนดให้กับค่านั้น
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 &&;
หรือ_อื่น:
F ควรเรียกใช้พร้อมกับประเภทข้อผิดพลาดที่คาดหวัง และควรส่งคืนสิ่งที่คาดหวังซึ่งประเภทค่าควรเป็น T
หาก invoke_result_t<F, E>
เป็นความเชี่ยวชาญพิเศษใดๆ ก็ตามที่คาดไว้ (ซึ่งประเภทค่าควรเหมือนกับ T) ดังนั้น หากมีค่าอยู่ ค่าจะถูกส่งกลับใน invoke_result_t ของ F มิฉะนั้นจะส่งคืนผลลัพธ์ของการเรียกใช้ f
หาก invoke_result_t<F, E>
เป็นโมฆะ หากมีข้อผิดพลาด 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 และสร้าง T ด้วย args
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{};