17
votes

[temp.concept]/5 says:

A concept is not instantiated ([temp.spec]). [ Note: An id-expression that denotes a concept specialization is evaluated as an expression ([expr.prim.id]). [...]]

Does it mean that this rule bellow ([temp.point]/8) does not apply?

If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.


For example if this rule does not apply, this code bellow is well formed:

template<class T>
concept Complete = sizeof(T)==sizeof(T);

struct A;

constexpr inline bool b1 = Complete<A>; //Complete<A>==false;

struct A{};

constexpr inline bool b2 = Complete<A>; //Complete<A>==true;

This question is followed by this one

1
@bolov Or template<class A> :-PZereges
Are you sure the concept definition is well-formed when applied for b1?rubenvb
That concept is ill-formed upon definition IIUC.StoryTeller - Unslander Monica
@Oliv - The paragraph I linked says nothing about instantiation, it's about template definition and name lookup. I'd be shocked if one can conjure non-dependent identifiers willy-nilly in a concept.StoryTeller - Unslander Monica
FYI - the answer to this used to be Yes, but now it is No.Barry

1 Answers

11
votes

Can a concept evaluation depend on where it is evaluated?

No.

It used to be the case that this was true (as my answer before this edit stated), but it turns out that this severely inhibits compiler throughput (since you cannot cache the result of a concept check) and the motivation for having it to begin with was pretty weak. This was a very late change, adopted as part of P2104 in the Prague 2020 meeting which adds the following sentence to [temp.constr.atomic]:

If, at different points in the program, the satisfaction result is different for identical atomic constraints and template arguments, the program is ill-formed, no diagnostic required.

As a result, this:

template<class T>
concept Complete = sizeof(T) == sizeof(T);

struct A;
static_assert(!Complete<A>);
struct A {};
static_assert(Complete<A>);   

is ill-formed, NDR (practically speaking, Complete<A> will still be false after A becomes complete). In other words, we "memoize" concepts in the same way we "memoize" template instantiations.