I am trying to mimic the can-referece
exposition only concept, that can be found in the new C 20 iterator concepts.
Extracted from cppreferece
:
template <class I>
concept input_or_output_iterator =
requires(I i) {
{ *i } -> /*can-reference*/;
} &&
std::weakly_incrementable<I>;
So, I tried to implement the concepts, as follows:
/**
* @brief ALias for define that a template parameter T is referenceable = T&
*/
template<typename T>
using template_arg_with_ref = T&;
/**
* @brief satisfied if and only if the type is referenceable (in particular, not void)
*/
template<typename T>
concept can_reference = requires() { typename template_arg_with_ref<T>; };
/**
* @brief satisfied if and only if the type is dereferenceable (in particular, not void)
*/
template<typename T>
concept dereferenceable = requires(T& t) {
{ *t } -> can_reference;
};
which compiles perfectly fine using Clang 15.0.0
.
However, if I try to remove verbosity, an define directly that a type T
is referenceable, without the alias:
/**
* @brief satisfied if and only if the type is referenceable (in particular, not void)
*/
template<typename T>
concept can_reference = requires() { typename T&; };
/**
* @brief satisfied if and only if the type is dereferenceable (in particular, not void)
*/
template<typename T>
concept dereferenceable = requires(T& t) {
{ *t } -> can_reference;
};
the compiler complains, and throws the following error:
error: expected ';' at end of requirement
concept can_reference = requires() { typename T&; };
^
;
- Is not possible to use directly
T&
as shown above? - Or I am just making a syntax error, and don't know the correct way of write the concept without the alias type?
CodePudding user response:
The grammar for a type requirement is given in [expr.prim.req.type] and allows only for a (nested) type-name, not a more general type-id (which is used e.g. in template arguments).
A type-name (possibly prefixed with a nested-name-specifier) can only be the name of a type (including required template argument lists), but no other type specifiers can be included. Adding a reference qualifier, const
/volatile
qualifier or forming other compound types such as arrays, function types, etc. in the requirement is not allowed. This is in line with how typename
can be used in other contexts. It always can only have a nested type-name follow it.
So you always need to defer an alias or you can use the template argument of e.g. std::type_identity_t
:
typename std::type_identity_t<T&>;