Why does std::make_error_code(std::errc) exist?

Viewed 618

I understand the difference between std::error_code and std::error_condition, and I understand that std::errc is an "error condition" enum and not an "error code" enum. I understand how to compare resulting std::error_code values against "error conditions" and so on. I have read Chris Kohlhoff's blog post about these types several times over the years. I have used these types and extensions to them in production code.

However, I do not understand why std::make_error_code(std::errc) exists.

It doesn't seem to be necessary for comparing actual std::error_code values against std::error_condition values: there is std::make_error_condition(std::errc) and conversions to std::error_condition and special comparison overloads for all of that.

The function's existence is especially puzzling because std::is_error_code_enum_v<std::err> is false for std::errc. Presumably that is to prevent implicitly converting std::errc to std::error_code via std::make_error_code(std::errc), but it isn't clear to me why preventing that is desirable when std::make_error_code(std::errc) exists. In other words, if you shouldn't make an std::error_code out of std::errc, why is there a function that does just that? And if you should, why is that implicit constructor disabled?

Is it std::errc a special case because code often wants to actually produce a real std::error_code in the std::generic_category() with an std::errc value? In other words, is std::errc in some ways both an "error code" and an "error condition" enumeration? (And, if so, why isn't std::is_error_code_enum_v<std::errc> true?)

Is it a special case for some other reason?

Are user-defined error conditions enums supposed to also offer make_error_code() like std::errc does, or just make_error_condition()?

1 Answers

std::errc defines the values of portable error; a plain (factually, quite limited), set of error code values.

std::error_code is a platform-dependent error which contains an error code value and a reference to an object of the error category object.


From the side of program design, just there is no good reason for the implicit conversion from std::errc to std::error_code. They logically very different set of errors: plain vs. grouping into categories (sources) standard set of errors vs. environment (platform and standard library implementation) dependent set of errors.

Conversions between the codes are not just changing a type or digital representation, it generally is environment-dependent logic.

A non-member function for such conversion is a quite natural solution.


From the side of implementation, they are not fundamental types so that compilers would specifically support conversion from and to the types; std::errcis implemented as class enum enumeration and cannot implement a conversion operator function as a class would; std::error_code is a class, so could implement the non-explicit constructor from std::errc, which support the implicit conversion, as it does for std::io_errc and std::future_errc (*), but logically correspondence of the different sets of errors is just not a concern of std::error_code, it would violate principles of object-oriented programming (specifically, it would be inappropriate distribution of responsibility over the code entities).


(*) - std::io_errc and std::future_errc (as well as other error code enumerations having ) are implicitly convertible to std::error_code because they just are the same errors as std::error_code store - std::error_code store exactly the same error code value and a reference to corresponded category of the error object; the errors sets are just subsets of the whole set which storing supported with std::error code.


The implicit conversion just would make program design worse and error-prone (specifically, illogical distribution of responsibility over the code and prone to covert and undesired conversion).

Related