This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c++/67070] [concepts] Concept with negation and disjunction not checked correctly


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67070

--- Comment #7 from Andrew Sutton <andrew.n.sutton at gmail dot com> ---
We haven't evaluated constraints as expressions in a long time (since
post-Rapperswil I think).

I don't think this is a good idea, but mostly because I'm not sure what the
instantiation/satisfaction semantics are. Consider:

template<typename T>
concept bool C() { return T::value; }

template<typename T> void f(T); // #1
template<C T> void f(T);        // #2

f(0); // ill-formed or #1?

If you evaluate constraints as expressions, then how is C<T>() instantiated? If
it's instantiated like a regular function, then the program should be
ill-formed since we're in a different instantiation context (in exactly the
same way this would fail for a function with a deduced return type).

We might alternatively evaluate concept checks by always evaluating them in a
SFINAE context, and defining, so that C<T>() returns true iff its constraint is
satisfied. Here, T::value (for int) yields a substitution failure and is not
satisfied. So #1 is chosen.

But these semantics actually do something a little weird for !. It let's you
write checks for when substitution fails or a constraint is not satisfied.

template<typename T>
  requires !C<T>()
void g();

g() is selected whenever C<T>() is not satisfied, or if substitution into
C<T>() fails. Those semantics were not considered in the original design. A
predicate constraint should evaluate a valid predicate. Substitution failure is
a kind of higher-order property of the system.

I'm also worried that evaluating constraints in this way would force us to
consider extending the logical system to support negation. And it's not always
obvious what the semantics of things like:

  !requires { typename T::type; }

would mean. Is it that T::type must not exist? Is it that T::type is not
required to exist? There are very good reasons to select both.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]