Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A requires expression is a C++20 language construct that evaluates to a boolean prvalue at compile-time, indicating whether a specified set of syntactic and semantic requirements are satisfied. It acts as a compile-time predicate, allowing the compiler to verify the validity of expressions, types, and constraints in an unevaluated context.
template <typename T>
concept Addable = requires(T a, T b) {
    a + b;
};
A requires expression defines an optional parameter list and a sequence of requirements. The parameters are local variables that are never instantiated or evaluated at runtime; they exist solely to act as operands within the requirement sequence. The compiler evaluates these requirements in lexical order. If any requirement is ill-formed or evaluates to false, the entire requires expression immediately short-circuits and yields false. Otherwise, it yields true. There are four distinct types of requirements that can be placed inside a requires expression:

1. Simple Requirements

A simple requirement asserts that an arbitrary expression is well-formed. The compiler verifies semantic rules, including type checking, overload resolution, and access control (e.g., ensuring a called member function is public). The compiler does not evaluate the expression’s result or check its return type.
template <typename T>
concept Computable = requires(T a, T b) {
    a + b;       // The expression 'a + b' must be well-formed
    a.compute(); // The member function 'compute()' must exist, be accessible, and be callable
};

2. Type Requirements

A type requirement asserts that a specific type is well-formed and exists. It is always prefixed with the typename keyword. This is primarily used to verify the existence of nested types, type aliases, or dependent class template instantiations.
template <typename T>
concept Iterable = requires {
    typename T::value_type; // T must have a nested type named 'value_type'
    typename T::iterator;   // T must have a nested type named 'iterator'
};

3. Compound Requirements

A compound requirement asserts the validity of an expression, and optionally asserts that it does not throw exceptions (noexcept), and/or asserts that its return type satisfies a specific concept. The expression is enclosed in braces, optionally followed by noexcept, and optionally followed by -> and a concept constraint.
#include <concepts>
#include <cstddef>
#include <string>

template <typename T>
concept StringContainer = requires(T a) {
    // Must be well-formed, must not throw, and return type must satisfy std::convertible_to
    { a.size() } noexcept -> std::convertible_to<std::size_t>;
    
    // Must be well-formed, and return type must exactly match std::string
    { a.name() } -> std::same_as<std::string>;
};

4. Nested Requirements

A nested requirement evaluates an additional boolean constant expression or concept. It is prefixed with the requires keyword. Unlike simple requirements, which only check if an expression is well-formed, a nested requirement checks if an expression evaluates to true.
#include <concepts>

template <typename T>
concept LargeDefaultConstructible = requires(T a) {
    requires sizeof(T) >= 4;                // The boolean expression must evaluate to true
    requires std::default_initializable<T>; // The concept must be satisfied
};

Lexical Distinction: Expression vs. Clause

A strict technical distinction exists between a requires expression and a requires clause.
  • Requires Clause: Appears in template declarations to constrain the template (e.g., template <typename T> requires Concept<T>).
  • Requires Expression: The construct defined above, which yields a boolean value.
When an ad-hoc requires expression is used directly within a requires clause, the requires keyword appears twice consecutively:
// 'requires' clause followed by a 'requires' expression
template <typename T>
requires requires (T x) { x.draw(); } 
void render(T item);
Master C++ with Deep Grasping Methodology!Learn More