[cfe-dev] Roadmap for a Concepts implementation P0734R0, currently merged into C++20 draft

Hubert Tong via cfe-dev cfe-dev at lists.llvm.org
Sat Nov 18 11:04:57 PST 2017

On Sat, Nov 18, 2017 at 11:58 AM, Saar Raz <saarraz1 at gmail.com> wrote:

>> 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.
>> void foo(int, int);
>> template <typename T>
>> concept C = requires (T t) { ::foo(t); };
>> constexpr bool a = C<int>;
>> void foo(int, int = 0);
>> constexpr bool b = C<int>;
>> static_assert(a != b);
> 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?
> 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).
There are indeed things that can be cached (like an atomic constraint of
::std::is_union_v<T>). Even if the constraint expressed by the concept
specialization cannot be entirely cached, the constraint can be rewritten
when cacheable portions are evaluated.

> I'd say that's premature optimization but it impacts the design quite
> substantially - do we model concepts specializations as Decls or not?
If I understand you correctly, you are saying that the trade-off is
uncertain on whether using Decls would buy us enough for the cost of having
Using Decls or not affects how we should refer to the concept
specializations from expression nodes that name fully resolved concept
If we do not use the Decls to keep enough information around, then they
only form an extra layer of indirection.

Other than that, the purist in me says that concept specializations are
merely a pair of concept template and a set of template arguments. There is
not even an AST with the arguments substituted in.

>> 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).
> What worries me about checking for satisfaction with && and || is the
> following:
> [temp.constr.atomic]: "[Example:
>   template<typename T>
>   concept C = sizeof(T) == 4 && !true; // requires atomic constraints
>                                      // sizeof(T) == 4 and !true
>   template<typename T>
>   struct S {
>     constexpr operator bool() const { return true; }
>   };
>   template<typename T>
>     requires (S<T>{})
>       void f(T); // #1
>   void f(int); // #2
>   void g() {
>   f(0); // error: expression S<int>{} does not have type bool
>         // while checking satisfaction of deduced arguments of #1,
>         // even though #2 is a better match
>   }
> — end example ]"
> By using regular Exprs we cannot enforce the bool-ness of operands.
I think this depends on timing. I am not sure how eager Clang is in
performing semantic analysis that would trigger implicit conversions. We
probably need to hamper resolution of the && and || operators somehow while
we are in a constraint, but not atomic constraint, context. I believe that
would be sufficient to prevent the type of atomic constraints from being
coerced early.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20171118/7fabcc29/attachment.html>

More information about the cfe-dev mailing list