C++ Logo

std-discussion

Advanced search

Re: atomic constraint rules vs requires-clause rules

From: Andrew Schepler <aschepler_at_[hidden]>
Date: Thu, 20 Feb 2025 19:41:55 -0500
On Thu, Feb 20, 2025 at 6:37 PM mauro russo via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> > I see what you're saying. Perhaps any nested SFINAE contexts,
> > i.e. an atomic constraint or the body of a requires-expression,
> > should be considered to not be in the immediate context of the
> > enclosing expression, so that only the innermost enclosing
> > SFINAE context is considered to be unsatisfied, or evaluates
> > to false. I think this could be a viable core issue.
>
>
This makes sense. And for an example where it actually makes a difference,
we just need:

template<typename T>
requires ! requires { T::value; }
int func() { return 0;}

int a = func<int>();

Here we want to make sure the semantics of "T::value" aren't checked when
substituting into the atomic constraint with expression "! requires {
T::value; }", so that the requires-expression rules can determine the value
is false, and then the constraint is in fact satisfied.


> I would say that a couple of notes may fix the problem:
>
> 1) in [temp.constr.atomic], avoid the content (requires-seq) of a
> requires-expression to be considered part of the immediate context for the
> atomic constraint
>
> 2) in [expr.prim.req.nested], avoid the content (constrained-expression)
> of the nested requirement to be considered part of the immediate context
> for the nested requirement (in terms of what [expr.prim.req.general]-p5
> states)
>

I think the nested-requirement case is already covered by "Substitution of
template arguments into a nested-requirement does not result in
substitution into the constraint-expression other than as specified in
[temp.constr.constr]." Maybe that could be rephrased in terms of "the
immediate context" to be more consistent - or maybe that would instead be
more confusing given the state of that phrase "the immediate context".

I'd consider adding to the note in [temp.deduct.general]/7, which currently
explains how a function's noexcept-specifier is instantiated, instead of
during the TAD substitutions in the "deduction substitution loci". A
template's constraints are a similar thing closely associated with the
template declaration, but as you're clarifying, the substitution happens in
a different way. Although in this case checking constraints always happens
immediately after the TAD substitution (paragraph 5), it would still make
clear that paragraph 8 "If a [TAD] substitution results in an invalid type
or expression..." does not apply.

 -- Andrew Schepler

Received on 2025-02-21 00:42:09