c++ - How would you use Alexandrescu's Expected<T> with void functions? -
so ran across (imho) nice thought of using composite construction of homecoming value , exception - expected<t>
. overcomes many shortcomings of traditional methods of error handling (exceptions, error codes).
see andrei alexandrescu's talk (systematic error handling in c++) , its slides.
the exceptions , error codes have same usage scenarios functions homecoming , ones don't. expected<t>
, on other hand, seems targeted @ functions homecoming values.
so, questions are:
have of triedexpected<t>
in practice? how apply idiom functions returning nil (that is, void functions)? update:
i guess should clarify question. expected<void>
specialization makes sense, i'm more interested in how used - consistent usage idiom. implementation secondary (and easy).
for example, alexandrescu gives illustration (a bit edited):
string s = readline(); auto x = parseint(s).get(); // throw on error auto y = parseint(s); // won’t throw if (!y.valid()) { // ... }
this code "clean" in way flows naturally. need value - it. however, expected<void>
1 have capture returned variable , perform operation on (like .throwiferror()
or something), not elegant. , obviously, .get()
doesn't create sense void.
so, code if had function, toupper(s)
, modifies string in-place , has no homecoming value?
have of tried expected; in practice?
it's quite natural, used before saw talk.
how apply idiom functions returning nil (that is, void functions)?
the form presented in slides has subtle implications:
the exception bound value. it's ok handle exception wish. if value ignored reasons, exception suppressed.this not hold if have expected<void>
, because since nobody interested in void
value exception ignored. forcefulness force reading expected<t>
in alexandrescus class, assertions , explicit suppress
fellow member function. rethrowing exception destructor not allowed reasons, has done assertions.
template <typename t> struct expected; #ifdef ndebug // no asserts template <> class expected<void> { std::exception_ptr spam; public: template <typename e> expected(e const& e) : spam(std::make_exception_ptr(e)) {} expected(expected&& o) : spam(std::move(o.spam)) {} expected() : spam() {} bool valid() const { homecoming !spam; } void get() const { if (!valid()) std::rethrow_exception(spam); } void suppress() {} }; #else // asserts, check if homecoming value checked // if assertions succeed, other code right // note: not write "assert(expected.valid());" template <> class expected<void> { std::exception_ptr spam; mutable std::atomic_bool read; // threadsafe public: template <typename e> expected(e const& e) : spam(std::make_exception_ptr(e)), read(false) {} expected(expected&& o) : spam(std::move(o.spam)), read(o.read.load()) {} expected() : spam(), read(false) {} bool valid() const { read=true; homecoming !spam; } void get() const { if (!valid()) std::rethrow_exception(spam); } void suppress() { read=true; } ~expected() { assert(read); } }; #endif expected<void> calculate(int i) { if (!i) homecoming std::invalid_argument("i must non-null"); homecoming {}; } int main() { calculate(0).suppress(); // suppressing must explicit if (!calculate(1).valid()) homecoming 1; calculate(5); // assert fails }
c++ c++11 error-handling runtime-error
No comments:
Post a Comment