Spec-Zone.ru › C++

Требует выражение (с C++20)

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

Синтаксис

requires { requirement-seq }
requires ( parameter-list (необязательно) ) { requirement-seq }
parameter-list - список параметров, разделённых запятыми, аналогичный списку параметров функции, за исключением того, что необязательные аргументы запрещены, и он не может заканчиваться многоточием (кроме многоточия, обозначающего раскрытие пакета). Эти параметры не имеют памяти, связи или жизненного цикла и используются только для помощи в указании требований. Эти параметры находятся в области видимости до закрытия } requirement-seq.
requirement-seq - последовательность требований, каждое требование — одно из следующих:
  • простое требование
  • требования к типу
  • составные требования
  • вложенные требования

Объяснение

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

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

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

template<class T>
concept C = requires
{
    new int[-(int)sizeof(T)]; // invalid for every T: ill-formed, no diagnostic required
};

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

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

Простое требование — это произвольное выражение, которое не начинается со слова requires. Оно утверждает, что выражение является допустимым. Выражение является неоцениваемым операндом; проверяется только корректность языка.

template<typename T>
concept Addable = requires (T a, T b)
{
    a + b; // "the expression a+b is a valid expression that will compile"
};
 
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; // required nested member name
    typename S<T>;     // required class template specialization
    typename Ref<T>;   // required alias template substitution
};
 
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> is valid and names a type
    { CommonType<T, U>{std::forward<T>(t)} }; 
    { CommonType<T, U>{std::forward<U>(u)} }; 
};

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

Составное требование имеет вид

{ expression } noexcept(необязательно) return-type-requirement (необязательно) ;
return-type-requirement - -> type-constraint

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

1) Аргументы шаблона (если таковые имеются) подставляются в expression;
2) Если noexcept используется, expression не должен быть способным генерировать исключения;
3) Если return-type-requirement присутствует, то:
a) Аргументы шаблона подставляются в return-type-requirement;
b) decltype((expression)) должно удовлетворять ограничению, наложенному type-constraint. В противном случае, окружающее выражение requires false.
template<typename T>
concept C2 = requires(T x)
{
    // the expression *x must be valid
    // AND the type T::inner must be valid
    // AND the result of *x must be convertible to T::inner
    {*x} -> std::convertible_to<typename T::inner>;
 
    // the expression x + 1 must be valid
    // AND std::same_as<decltype((x + 1)), int> must be satisfied
    // i.e., (x + 1) must be a prvalue of type int
    {x + 1} -> std::same_as<int>;
 
    // the expression x * 1 must be valid
    // AND its result must be convertible to T
    {x * 1} -> std::convertible_to<T>;
};

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

Вложенное требование имеет вид

requires constraint-expression ;

Он может использоваться для задания дополнительных ограничений в терминах локальных параметров. 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)>; // nested: "Same<...> evaluates to true"
    { a.~T() } noexcept; // compound: "a.~T()" is a valid expression that doesn't throw
    requires Same<T*, decltype(new T)>; // nested: "Same<...> evaluates to true"
    requires Same<T*, decltype(new T[n])>; // nested
    { delete new T }; // compound
    { delete new T[n] }; // compound
};

Примечание

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

template<typename T>
concept Addable = requires (T x) { x + x; }; // requires-expression
 
template<typename T> requires Addable<T> // requires-clause, not requires-expression
T add(T a, T b) { return a + b; }
 
template<typename T>
    requires requires (T x) { x + x; } // ad-hoc constraint, note keyword used twice
T add(T a, T b) { return a + b; }

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

requires

См. также

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/requires

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API