<div dir="ltr"><div class="gmail_quote"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Concepts are not instantiated. They are evaluated for satisfaction. Much of the wording to allow "global" knowledge to be used for instantiating templates relies on point-of-instantiation.<br></div><div><br>void foo(int, int);<br><br>template <typename T><br>concept C = requires (T t) { ::foo(t); };<br><br>constexpr bool a = C<int>;<br><br>void foo(int, int = 0);<br>constexpr bool b = C<int>;<br><br>static_assert(a != b);</div></div></div></div></blockquote><div> </div></div></div><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div>Mmm, good example. So does that mean we cannot hope to cache results of concept evaluations? That sounds like quite the performance hit for highly conceptized code (e.g. ranges), is it not?</div><div><br></div><div>Maybe we can form some sort of condition under which a concept evaluation result may be cached? There are, I think, at least some expression classes that cannot change once the concept has been instantiated with a type (e.g. expressions that do not involve namespace lookup).</div><div>I'd say that's premature optimization but it impacts the design quite substantially - do we model concepts specializations as Decls or not?</div></div></div></div><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>My understanding is that it is viable for conjunction and disjunction to be represented by && and || for satisfaction checking; it would be context-dependent during the evaluation whether the node is within an atomic constraint (and thus not representative of a conjunction or disjunction). <br></div></div></div></div></blockquote></div></div></div><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><div>What worries me about checking for satisfaction with && and || is the following:</div><div>[temp.constr.atomic]: "[Example:</div><div>  template<typename T></div><div>  concept C = sizeof(T) == 4 && !true; // requires atomic constraints</div><div>                                     // sizeof(T) == 4 and !true</div><div>  template<typename T></div><div>  struct S {</div><div>    constexpr operator bool() const { return true; }</div><div>  };</div><div>  </div><div>  template<typename T></div><div>    requires (S<T>{})</div><div>      void f(T); // #1</div><div>      </div><div>  void f(int); // #2</div><div>  </div><div>  void g() {</div><div>  f(0); // error: expression S<int>{} does not have type bool</div><div>        // while checking satisfaction of deduced arguments of #1,</div><div>        // even though #2 is a better match</div><div>  }</div><div>— end example ]"</div><div>By using regular Exprs we cannot enforce the bool-ness of operands.</div><div><br></div></div></div></div></div></div>