Exploring Requires Expressions
Distinguish among the different types of requires expressions.
Syntax for defining requires expressions
A requires expression may be a complex expression, as seen earlier in the example with the container concept. The actual form of a requires expression is very similar to function syntax and is as follows:
requires (parameter-list) { requirement-seq }
The parameter-list
is a comma-separated list of parameters. The only difference from a function declaration is that default values are not allowed. However, the parameters that are specified in this list do not have storage, linkage, or lifetime. The compiler doesn’t allocate any memory for them; they’re only used to define requirements. However, they do have a scope, and that’s the closing curly brace of the requires expression.
The requirements-seq
is a sequence of requirements. Each such requirement must end with a semicolon, like any statement in C++. There are four types of requirements:
Simple requirements
Type requirements
Compound requirements
Nested requirements
These requirements may refer to the following:
Template parameters that are in scope
Local parameters introduced in the parameter list of the requires expression
Any other declaration that is visible from the enclosing context
In this lesson, we’ll explore all the mentioned types of requirements. To start with, we’ll look at the simple requirements.
Simple requirements
A simple requirement is an expression that is not evaluated but only checked for correctness. The expression must be valid for the requirement to be evaluated to the value true
. The expression must not start with the requires
keyword because that defines a nested requirement (which will be discussed later).
We already saw examples of simple statements when we defined the arithmetic
and container
concepts earlier. Let’s see a few more:
template<typename T>concept arithmetic = requires{std::is_arithmetic_v<T>;};template<typename T>concept addable = requires(T a, T b){a + b;};template<typename T>concept logger = requires(T t){t.error("just");t.warning("a");t.info("demo");};
The first concept, arithmetic
, is the same one we defined earlier. The std::is_ arithmetic_v<T>
expression is a simple requirement. Notice that when the parameter list is empty, it can be completely omitted, as seen in this case, where we only check ...