On Mon, Jan 15, 2018 at 8:20 AM, Peter Dimov via Boost < boost@lists.boost.org> wrote:
I should probably just add the relevant constexpr's to Boost.System. https://github.com/boostorg/system/commits/feature/constexpr
The only nontrivial change this entails is changing the member relational operators of error_category:
class error_category { public:
bool operator==(const error_category& rhs) const noexcept; bool operator!=(const error_category& rhs) const noexcept; bool operator<(const error_category& rhs) const noexcept; };
into nonmembers:
constexpr bool operator==(const error_category& lhs, const error_category& rhs) noexcept; constexpr bool operator!=(const error_category& lhs, const error_category& rhs) noexcept; bool operator<(const error_category& lhs, const error_category& rhs) noexcept;
For the first two, g++ complained that members of a non-literal class can't be constexpr (whereas clang had no problem with it.) The third one I moved out for consistency.
Nonmembers seem more idiomatic in either case; can someone think of an argument against having these out of the class?
Not to get into the weeds, but: (a) I don't care where relational operators are defined, but (b) Users should not be encouraged to override implementations of relational operators themselves The design should/does allow for "equality/equivalence" override for user-custom domains, where that single (user-provided) implementation is used by the relational operators, such as through: *- virtual bool std::error_category::equivalent(int, const std::error_condition&) const noexcept; *- virtual bool std::error_category::equivalent(const std::error_code&,int) const noexcept; I realize you're talking about equivalence on the 'std::error_category' itself, so std::-provided relational operators anywhere are fine (the user should never override). If we (someday) wanted user-explicit override for comparing 'std::error_category' instances, we should provide that single function that the user can re-implement (which is then used by the relational operators themselves). Thus, it seems that the relational operators could go anywhere, and nobody should care. Summary: (1) I want the 'constexpr' (2) Its fine with me if relational operators are no longer member functions of 'std::error_category' (3) Ditto for 'std::error_code' and 'std::error_condition' (4) I don't think users should provide custom implementations of relational operators (customization is elsewhere) If we were to venture "into the weeds", the question would become: *- is comparison *exact-match* or *semantically-equivalent*? (i.e., are two separate categories permitted to "compare-equal"?) Possible rationalizations: (1) Two separate 'std::error_category' instances may be semantically the same category, but different instances (and "could' compare equal). This would also "smooth-over" the singleton 'std::error_category' ODR issue. (2) I've seen "enum-hierarchies" for error codes, where the "subset-categories" actually merely represent subsets within the parent category. Those sub-categories could compare equal to the parent-category, because they literally represent windows into the same parent-category. But of course, the current design is "identity" comparison for 'std::error_category'; and I want 'constexpr' more than I would want semantic equivalence. I have the opposite opinion for 'std::error_code', where I *always* want semantic equivalence, and *never* exact-match testing (where the current design tests for exact-match 'code==code' and semantic compare for 'code==condition'). --charley