On 01/12/18 22:03, Peter Dimov via Boost wrote:
Andrey Semashev wrote:
void foo(error_code& err) { // Do stuff... err = make_error_code(success); // error_code(0, my_category) } ... I suppose, you could argue that I could avoid `err` initialization in `foo`, but that is a matter of taste and whether you want to rely on the initial state of `err` on entry into `foo`.
No, I'm not going to argue that; it's idiomatic to clear `err` on entry:
void foo( error_code& err ) { err.clear(); // do stuff }
with the alternative
err.assign( 0, err.category() );
being used nowadays to avoid the overhead in .clear caused by the "magic static" Niall talks about.
This latter "idiom" is obviously broken after NIall's suggested change though.
I don't think this matches my intent. The `foo` function belongs to the domain that defines error codes described by the `my_errors` enum and it is supposed to return one of those codes. Preserving whatever error category was set in `err` on entry does not achieve that. What I want is that `err` has `my_category` unconditionally on return from `foo`.
I'm also not happy to have to convert that initialization to
err = error_code();
because it loses information about the error category, which may be useful if I want to print `err` to log even if it is a success.
Interesting. You rely on there being different success error_codes?
Yes, mostly for diagnostic purposes. Although it may also be a useful feature to check the domain when comparing two error codes.
How would you suggest we solve the problem of zero being an error in some contexts?
Besides moving the check for the error code into the category? I suppose, `make_error_code` could perform some kind of mapping onto another enum that has success value of 0. It can be as simple as this: enum foreign_errors { error = 0, success = 1 }; enum class internal_errors { error = -1, success = 0 }; error_code make_error_code(foreign_errors ec) { return error_code(ec - 1, my_category); } error_code make_error_code(internal_errors ec) { return error_code(ec, my_category); } Another solution would be to make error category have a public member, which is cheap to access, that would return the "success" value. // std::error_category class error_category { int success_value; public: explicit error_category(int sv = 0) : success_value(sv) {} int get_success_value() const noexcept { return success_value; } }; class my_category final : public error_category { public: my_category() : error_category(1) {} }; bool error_code::operator bool() const { return value() != category().get_success_value(); }