Выражение requires (начиная с C++20)
Возвращает выражение prvalue типа bool, описывающее ограничения.
Синтаксис
requires { последовательность-требований }
|
|||||||||
requires ( список-параметров (необязательно) ) { последовательность-требований }
|
|||||||||
| список-параметров | — | список параметров, разделённых запятыми, как в объявлении функции, за исключением того, что аргументы по умолчанию не допускаются и он не может заканчиваться многоточием (кроме расширение пакета). Эти параметры не имеют класса памяти, связывания или времени жизни и используются только для помощи в определении требований. Эти параметры находятся в области действия до закрывающей } последовательности-требований.
|
| последовательность-требований | — | последовательность требований, каждое требование которого является одним из следующих:
|
Объяснение
Требования могут ссылаться на параметры шаблона, которые находятся в области видимости, на локальные параметры, введённые в список-параметров, и на любые другие объявлениям, видимые из окружающего контекста.
Подстановка аргументов шаблона в выражение requires, используемое в объявлении шаблонной сущности, может привести к формированию
недопустимых типов или выражений в их требованиях или нарушению семантических ограничений этих требований. В таких случаях выражение requires оценивается как false и не приводит к некорректной программе. Подстановка и проверка семантических ограничений выполняются в лексическом порядке и останавливаются, когда встречается условие, определяющее результат выражения requires. Если подстановка (если есть) и проверка семантических ограничений успешны, выражение-требования оценивается как true.
Если в выражении requires для каждого возможного аргумента шаблона произойдёт сбой подстановки, программа некорректна, диагностика не требуется:
template<class T>
concept C = requires
{
new int[-(int)sizeof(T)]; // недействительно для каждого T: неправильно сформировано,
// диагностика не требуется
};
Если выражение requires содержит недопустимые типы или выражения в своих требованиях и не появляется в объявлении шаблонной сущности, то программа некорректна.
Простые требования
Простое требование это произвольное выражение, которое не начинается с ключевого слова requires. Оно утверждает, что выражение допустимо. Выражение является невычисленным операндом; проверяется только языковая корректность.
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, за которым следует имя типа, необязательно уточнённое. Требование состоит в том, чтобы именованный тип был допустимым: это можно использовать для проверки существования определённого именованного вложенного типа, или того, что специализация шаблонного класса именует тип, или что специализация псевдонима шаблона именует тип. Требование типа, именующее специализацию шаблонного класса, не требует, чтобы тип был полным.
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)} };
};
Составные требования
Составное требование имеет вид
{ выражение } noexcept(необязательно) требование-типа-возврата (необязательно) ;
|
|||||||||
| требование-типа-возврата | — | -> ограничение-типа
|
и утверждает свойства именованного выражения. Проверка подстановки и семантических ограничений выполняется в следующем порядке:
decltype((expression)) должно соответствовать ограничению, налагаемому ограничением-типа. В противном случае заключённое в скобки выражение requires равно false.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 выражение-ограничение ;
|
|||||||||
Его можно использовать для указания дополнительных ограничений в терминах локальных параметров. Выражение-ограничения должно соответствовать подставленным аргументам шаблона, если таковые имеются. Подстановка аргументов шаблона во вложенное требование приводит к подстановке в выражение-ограничения только в той мере, в какой это необходимо для определения того, удовлетворяется ли выражение-ограничения.
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.
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; } // специальное ограничение, обратите внимание,
// что ключевое слово используется дважды
T add(T a, T b) { return a + b; }
Ключевые слова
Смотрите также
| Ограничения и концепты(C++20) | определяет требования к аргументам шаблона |