Look at this code. It contains two functions templates, neither can be instantiated with char *
, as t * 1
doesn't compile. However, if I put func1
into a requires expression of a concept, the concept is true
for char *
:
template <typename T>
void func1(T t) {
t * 1;
}
template <typename T>
auto func2(T t) {
return t * 1;
}
template <typename T>
concept foo = requires (T t) { func1(t); };
static_assert(foo<char *>); // assert doesn't fire, but func1<char *> is a non-compiling function
This compiles, even though func1
doesn't compile if it is instantiated with char *
. If I use func2
instead of func1
in the concept, then concept foo
becomes false
.
So it seems that the compiler doesn't instantiate func1
in the concept, but it does so for func2
, presumably because it has to determine the return type (as it is auto
).
I didn't find too much about this in expr.prim.req.simple:
"A simple-requirement asserts the validity of an expression. The expression is an unevaluated operand."
What does validity mean in this context? Where are the exact rules regarding when should the compiler instantiate the template?
The substitution of template arguments into a requires-expression can result in the formation of invalid types or expressions in the immediate context of its requirements ([temp.deduct.general]) or the violation of the semantic constraints of those requirements. In such cases, the requires-expression evaluates to
false
; it does not cause the program to be ill-formed. [...]
That is to say, validity of the expression is based on the immediate context. If something is ill-formed outside of the immediate context, then you get a hard error instead of a false
result. See here for discussion of what "immediate context" means. It is not formally defined in the standard.
Since the value of the requires-expression is based only on the validity in the immediate context, it will not actually instantiate any templates if all the information needed to determine the validity of the expression in the immediate context is already present without needing to perform that instantiation. See e.g. [temp.inst]/5
Unless a function template specialization is a declared specialization, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program. A function whose declaration was instantiated from a friend function definition is implicitly instantiated when it is referenced in a context that requires a function definition to exist or if the existence of the definition affects the semantics of the program. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
[Note: ... ]
The validity of a function call in the immediate context does not require the definition of the function to exist (unless the value of the call is needed at compile time; see [temp.inst]/8), since the function body isn't in the immediate context of the call. However, if the function has a deduced return type, its body must be instantiated to determine the return type, since the validity of the call clearly depends on the return type; you can't analyze the well-formedness of an expression without knowing the type of each entity that appears in it. If an ill-formed construct is instantiated in the body, a hard error occurs because the body isn't in the immediate context.