- does not allow attributes
- the declaration requirement checks for valid declaration and after that, it introduces a new name in that declaration.
- the initialization are all unevaluated
- this name can be used in subsequent requirements within the same body of 'requires' expression
examples:
(assume all these requires-expressions are within the template context)
1.) introduces type alias
requires {
// requires the type to be valid and then introduces 'There'
using There = foo<T>::here_with<U>::there;
requires ValidOne<There>;
requires ValidTwo<There>;
};
2.) variables introduced in decl-req. are not the same as local parameters
requires (A a, B b) {
do_something(a, b);
};
requires {
// this requires 'a' and 'b' to be default initialized
A a;
B b;
do_something(a, b);
};
3.) with initializers and auto
requires {
A a {}; // ok
A _ {}; // ok
B _ {}; // placeholder variable permitted, ok
{ use_this(a) } -> valid_return; // ok
{ use_this(_) } -> valid_return; // error, ambiguous _
// functions pointers allowed
auto (* fp) (A, B) -> void;
auto c = return_this(); // ok
some_constraint auto d = return_this(); // ok, checks if 'd' satisfies 'some_constraint'
A& e = std::declval<A&>(); // allows unevaluated initializers
};
4.) structured bindings
requires {
// checks if 'T' can be decomposed into three elements
auto [a, b, c] = std::declval<T>();
};
template <typename T>
concept decomposable = requires
{
auto [...args] = std::declval<T>();
// 'args' pack can be used in other requirements
// this is only allowed when the initializer is templated entity
};
5.) constexpr not allowed
requires
{
T t; // ok, if that initialization is allowed
const U u; ok, if that initialization is allowed
constexpr V v = some_initializer(); // error, 'constexpr' not allowed
use_nttp<N>; // ok, if 'N' is some non-type template parameter
use_nttp<u>; // error, unevaluated variable 'u' cannot be used as nttp
use_ttp<decltype(u)>; // ok
};
--