Boost logo

Boost :

Subject: Re: [boost] [system] Would it be possible to trial a breaking change to Boost.System and see what happens?
From: charleyb123 . (charleyb123_at_[hidden])
Date: 2018-01-15 18:00:34


On Mon, Jan 15, 2018 at 8:20 AM, Peter Dimov via Boost <
boost_at_[hidden]> 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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk