C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Allow using type alias in requires-clause

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Wed, 16 Aug 2023 11:56:24 -0400
On Wed, Aug 16, 2023 at 11:39 AM Kang Hewill via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Hello all C++ experts,
>
> I find it very convenient to allow using-type alias in the requires
> -clause.
>
> For complex type aliases, simplifying them with using-alias can reduce
> redundant spelling for subsequent constraint checks on the same type alias.
>
> Take the standard concept *indirectly-readable-impl*
> <https://eel.is/c++draft/iterator.concept.readable> as an example:
>
> template<class In>
> concept indirectly-readable-impl =
> requires(const In in) {
> typename iter_value_t<In>;
> typename iter_reference_t<In>;
> typename iter_rvalue_reference_t<In>;
> { *in } -> same_as<iter_reference_t<In>>;
> { ranges::iter_move(in) } -> same_as<iter_rvalue_reference_t<In>>;
> } &&
> common_reference_with<iter_reference_t<In>&&, iter_value_t<In>&> &&
> common_reference_with<iter_reference_t<In>&&, iter_rvalue_reference_t<In>&&> &&
> common_reference_with<iter_rvalue_reference_t<In>&&, const iter_value_t<In>&>;
>
> we can simplify it to:
>
> template<class In>
> concept indirectly-readable-impl =
> requires(const In in) {
> using value_type = typename iter_value_t<In>;
> using reference = typename iter_reference_t<In>;
> using rvalue_reference = typename iter_rvalue_reference_t<In>;
> { *in } -> same_as<reference>;
> { ranges::iter_move(in) } -> same_as<rvalue_reference>;
> requires common_reference_with<reference&&, value_type&>;
> requires common_reference_with<reference&&, rvalue_reference&>;
> requires common_reference_with<rvalue_reference&&, const value_type&>;
> };
>
> Do you think it's worth supporting this using-alias syntax in the requires
> -clause?
>
That seems reasonable to me, except that you need a story about alias
*templates*. Are you also proposing to support e.g.
    template<class A>
    concept Allocator = requires (const A& a) {
        *template<class T> using* rebound =
std::allocator_traits<A>::rebind<T>;
        rebound<int>(a);
        requires std::same_as<rebound<int>::value_type, int>;
    };
Does that close any doors to syntax we might want in the future?

If you can't support alias templates just as well as aliases, then you're
going to need *much* stronger motivation. I have the gut feeling that
permitting alias declarations in concepts might indeed simplify some
code... but the example you've actually presented here doesn't "simplify."
It makes the code exactly the same length, and IMHO *less* readable
(because now we have multiple ways of spelling the same types, making it
harder to follow what's going on and what's dependent on what).

Plus, the *major* change you made there doesn't have anything to do with
aliases — you merely moved the previously-subsumed sub-concepts into the
requires-expression. That could be done today, if we didn't care about
subsumption; and it *can't* be done tomorrow, if we *continue* to care
about subsumption. So your example is not only not-very-motivating, it's
also apples-to-oranges.

–Arthur

Received on 2023-08-16 15:56:38