requires
expression
(since C++20)
Возвращает 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
. Подстановка и проверка семантических ограничений выполняется в следующем порядке:
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; }
Ключевые слова
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам 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) | определяет требования к аргументам шаблона |