A requires-expression is a list of requirements that can be of different natures. Simple-requirements are expressions that do not
start with the keyword requires
and compound-requirements are expressions surrounded by curly brackets potentially followed by a
noexcept
specification and return type requirements.
In both cases, the expressions are not evaluated. They will only be checked for validity, and if the expression is invalid, the
requires-expression evaluates to false
.
When we write a concept check or a type predicate, the intent is usually to evaluate them, therefore, they don’t really belong in a
simple-requirement or a compound-requirement. Instead, they should either be used directly in a concept definition (outside of a
requires-expression) or, less often, as a nested-requirement (a requirement introduced by the requires
keyword within
the requires-expression).
This rule detects concept checks and standard type predicates (from the header <type_traits>
) in single and compound
requirements of requires-expressions.
Noncompliant code example
template<typename T>
concept TriviallyCopyable = requires {
std::copyable<T>; // Noncompliant
{std::is_trivally_copy_constructible_v<T>}; // Noncompliant
std::is_trivally_move_constructible<T>::value; // Noncompliant
};
This concept is always true
, for every type T
, because expressions such as std::copyable<T>
are always
well-formed.
Compliant solution
template<typename T>
concept TriviallyCopyable =
std::copyable<T> &&
std::is_trivially_copy_constructible_v<T> &&
std::is_trivially_move_constructible<T>::value;
Or:
template<typename T>
concept TriviallyCopyable = requires {
requires std::copyable<T>;
requires std::is_trivially_copy_constructible_v<T> &&
std::is_trivially_move_constructible<T>::value;
};