Namespaces
Variants

requires expression (since C++20)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Возвращает prvalue-выражение типа bool , которое описывает ограничения.

Содержание

Синтаксис

requires { requirement-seq } (1)
requires ( parameter-list  (необязательно) ) { requirement-seq } (2)
parameter-list - список параметров
requirement-seq - последовательность требований , каждое требование является одним из следующих:

Объяснение

Требования могут ссылаться на параметры шаблона, находящиеся в области видимости, на параметры parameter-list , а также на любые другие объявления, видимые из охватывающего контекста.

Подстановка аргументов шаблона в requires выражение, используемое в объявлении шаблонной сущности , может привести к формированию некорректных типов или выражений в его требованиях, или к нарушению семантических ограничений этих требований. В таких случаях requires выражение вычисляется в false и не приводит к некорректности программы. Подстановка и проверка семантических ограничений выполняются в лексическом порядке и останавливаются при достижении условия, определяющего результат requires выражения. Если подстановка (если применимо) и проверка семантических ограничений завершаются успешно, requires выражение вычисляется в true .

Если подстановка завершится неудачей в requires выражении для каждого возможного шаблонного аргумента, программа является некорректной, диагностика не требуется:

template<class T>
concept C = requires
{
    new int[-(int)sizeof(T)]; // недопустимо для любого T: некорректно сформировано, диагностика не требуется
};

Если requires выражение содержит недопустимые типы или выражения в своих требованиях и не находится внутри объявления шаблонной сущности , то программа является некорректной.

Локальные параметры

Выражение requires может вводить локальные параметры с использованием списка параметров . Эти параметры не имеют линковки, хранилища или времени жизни; они используются только как обозначения для определения требований.

Тип каждого параметра определяется тем же способом, что и определение фактического типа параметров функции:

template<typename T>
concept C = requires(T p[2])
{
    (decltype(p))nullptr; // OK, p имеет тип T*
};

Если выполняется любое из следующих условий, программа является некорректной:

template<typename T>
concept C1 = requires(T t = 0)  // Ошибка: t имеет аргумент по умолчанию
{
    t;
};
template<typename T>
concept C2 = requires(T t, ...) // Ошибка: завершается многоточием
{
    t;
};

Простые требования

выражение ;
expression - выражение, которое не начинается с requires


Простое требование утверждает, что expression является корректным. expression представляет собой невычисляемый операнд .

template<typename T>
concept Addable = requires (T a, T b)
{
    a + b; // "выражение «a + b» является корректным выражением, которое скомпилируется"
};
template<class T, class U = T>
concept Swappable = requires(T&& t, U&& u)
{
    swap(std::forward<T>(t), std::forward<U>(u));
    swap(std::forward<U>(u), std::forward<T>(t));
};

Требование, которое начинается с ключевого слова requires , всегда интерпретируется как вложенное требование. Таким образом, простое требование не может начинаться с непомещенного в скобки requires выражения.

Требования к типам

typename идентификатор ;
identifier - (возможно квалифицированный) identifier (включая simple template identifier )


Требование типа утверждает, что тип, названный identifier , является валидным: это может использоваться для проверки существования определённого именованного вложенного типа или что специализация шаблона класса/алиаса именует тип. Требование типа, называющее специализацию шаблона класса, не требует полноты типа.

template<typename T>
using Ref = T&;
template<typename T>
concept C = requires
{
    typename T::inner; // требуется вложенное имя члена
    typename S<T>;     // требуется специализация шаблона класса
    typename Ref<T>;   // требуется подстановка шаблона псевдонима
};
template<class T, class U>
using CommonType = std::common_type_t<T, U>;
template<class T, class U>
concept Common = requires (T&& t, U&& u)
{
    typename CommonType<T, U>; // CommonType<T, U> является валидным и обозначает тип
    { CommonType<T, U>{std::forward<T>(t)} }; 
    { CommonType<T, U>{std::forward<U>(u)} }; 
};

Составные требования

{ выражение }; (1)
{ выражение } noexcept ; (2)
{ выражение } -> ограничение-типа ; (3)
{ выражение } noexcept -> ограничение-типа ; (4)
expression - выражение
type-constraint - ограничение constraint


Составное требование утверждает свойства expression . Подстановка и проверка семантических ограничений выполняется в следующем порядке:

1) Аргументы шаблона (если есть) подставляются в expression .
2) Если присутствует noexcept , expression не должен быть потенциально выбрасывающим исключения .
3) Если type-constraint присутствует, то:
a) Аргументы шаблона подставляются в type-constraint .
б) decltype ( ( expression  ) ) должен удовлетворять ограничению, наложенному type-constraint . В противном случае, объемлющее requires выражение является false .

expression является невычисляемым операндом .

template<typename T>
concept C2 = requires(T x)
{
    // выражение *x должно быть валидным
    // И тип T::inner должен быть валидным
    // И результат *x должен быть конвертируемым в T::inner
    {*x} -> std::convertible_to<typename T::inner>;
    // выражение x + 1 должно быть валидным
    // И std::same_as<decltype((x + 1)), int> должно быть удовлетворено
    // т.е. (x + 1) должно быть prvalue типа int
    {x + 1} -> std::same_as<int>;
    // выражение x * 1 должно быть валидным
    // И его результат должен быть конвертируемым в T
    {x * 1} -> std::convertible_to<T>;
};

Вложенные требования

requires constraint-expression ;
constraint-expression - выражение, представляющее constraints


Вложенное требование может использоваться для указания дополнительных ограничений в терминах локальных параметров. constraint-expression должно удовлетворяться подставленными аргументами шаблона, если таковые имеются. Подстановка аргументов шаблона во вложенное требование вызывает подстановку в constraint-expression только в той степени, которая необходима для определения, удовлетворяет ли constraint-expression условию.

template<class T>
concept Semiregular = DefaultConstructible<T> &&
    CopyConstructible<T> && CopyAssignable<T> && Destructible<T> &&
requires(T a, std::size_t n)
{  
    requires Same<T*, decltype(&a)>; // вложенное: "Same<...> вычисляется как true"
    { a.~T() } noexcept; // составное: "a.~T()" является валидным выражением, которое не выбрасывает исключений
    requires Same<T*, decltype(new T)>; // вложенное: "Same<...> вычисляется как true"
    requires Same<T*, decltype(new T[n])>; // вложенное
    { delete new T }; // составное
    { delete new T[n] }; // составное
};

Примечание

Ключевое слово requires также используется для введения requires clauses .

template<typename T>
concept Addable = requires (T x) { x + x; }; // выражение requires
template<typename T> requires Addable<T> // предложение requires, не выражение requires
T add(T a, T b) { return a + b; }
template<typename T>
    requires requires (T x) { x + x; } // ad-hoc ограничение, обратите внимание на двойное использование ключевого слова
T add(T a, T b) { return a + b; }

Ключевые слова

requires

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
CWG 2560 C++20 было неясно, корректируются ли типы параметров в requires выражениях также корректируются
CWG 2911 C++20 все выражения, появляющиеся внутри requires
выражений, были невычисляемыми операндами
только некоторые
выражения являются

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 7.5.7 Выражения requires [expr.prim.req]
  • Стандарт C++20 (ISO/IEC 14882:2020):
  • 7.5.7 Выражения requires [expr.prim.req]

Смотрите также

Ограничения и концепции (C++20) определяет требования к аргументам шаблона