https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67070
--- Comment #9 from Jason Merrill <jason at gcc dot gnu.org> --- (In reply to Andrew Sutton from comment #7) > 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. Yes, that's a question. The implementation currently does the latter. > But these semantics actually do something a little weird for !. It lets 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. It seems to me that we should only substitute into C<T> in the process of satisfaction: in this case, if the type constraint is not satisfied, we don't substitute into the rhs of &&. It strikes me as strange that in some cases we would substitute into both sides and in other cases only one side. > I'm also worried that evaluating constraints in this way would force us to > consider extending the logical system to support negation. I think evaluating constraints in this way is a way to *avoid* needing to extend the logical system to support negation, by allowing && shortcuts within evaluation of a single concept.