رأس واحد std::التنفيذ المتوقع باستخدام C++ 20.
تنفذ المكتبة هذين المقترحين:
يوفر هذا التنفيذ المتوقع في مساحة الاسم. لذلك، لأي استخدام لـ std::expected، استخدم rd::expected.
std::expected هي آلية لمعالجة الأخطاء. هذا مشابه جدًا لنتيجة Rust::result. std::expected يحتوي أساسًا على نتيجة أو خطأ.
من المحتمل أن يكون هناك سببان لعدم استخدام الاستثناءات "دائمًا":
أثناء كتابة أي مكتبة، يشكل ذلك مشكلة كبيرة في معالجة الأخطاء. في المكتبة، إذا اخترنا طرح استثناء في حالة الخطأ، فإننا نختار مستخدم المكتبة. قد تكون حالة الخطأ في المكتبة حالة استثنائية أو لا تكون في سياق التطبيق الذي يستخدم تلك المكتبة.
يوفر std::expected بديلاً قياسيًا للاستثناء الذي يمكن استخدامه لحالة الخطأ التي ليست استثنائية في سياق التطبيق.
أثناء قول هذا، تجدر الإشارة إلى أن الاستثناءات رائعة لحالات الذعر. وهناك العديد من حالات الذعر الواضحة، والتي ينبغي استخدام الاستثناءات فقط فيها.
يُستخدم error_code ليكون أبسط آلية لمعالجة الأخطاء. تاريخيًا، يعد error_code عددًا صحيحًا بسيطًا، وهو ليس جيدًا لسياق الأخطاء الغني.
في الوقت الحاضر، يوفر رأس C++ <system_error> رمز خطأ أكثر ثراءً. ومع ذلك، يؤدي error_code إلى احتكار قناة العودة. وبالتالي يجب إخراج القيمة باستخدام قناة أخرى.
كما أنه يفرض عليك كتابة الشرط بعد كل استدعاء دالة.
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);
ثالثا::مهمة غير متوقعة:
يعين الخطأ إلى المتوقع
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 &&;
أو_آخر:
يجب أن يكون F قابلاً للاستدعاء مع نوع الخطأ المتوقع ويجب أن يُرجع المتوقع الذي يجب أن يكون نوع قيمته T.
إذا كان invoke_result_t<F, E>
هو أي تخصص متوقع (يجب أن يكون نوع قيمته هو نفس T)، ثم إذا كانت هناك قيمة، فسيتم إرجاع القيمة ملفوفة في invoid_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 باستخدام الوسائط.
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{};