Type constraints restrict by limiting the type accepted. By this you can only accept types, which contain some properties or a set of subtypes.
Variable concept:
template<typename T>
concept bool TypeHasTypeVar = requires { typename T::type; };
Function concept:
template<typename T>
concept bool TypeHasTypeFn ()
{
return requires { typename T::type; };
}
The previous concepts requires the type T
to have a subtype ::type
, such that when replacing T
in T::type
yields a valid type.
The struct foo_type
has a C++11 typedef, also known as a using
. It introduces a new type called type
in foo_type
.
struct foo_type
{
using type = int;
};
Replacing T
in T::type
where T = foo_type
, will yield a valid type. foo_type::type
is a valid type, and compilation may resume because this constraint is satisfied.
If you were a library author, you can use type constraints to get early error messages for your users if their user supplied types does not implement the required set of types.
Most STL containers have a key_type
and value_type
. If you require such type, you can require it with a type constraint.
Implicit conversion checks if a operation between two concepts result in an other type without specifying the type explicitly.
template<typename T>
concept bool ImplicitBoolVar = requires(T a, T b)
{
{ a == b } -> bool;
};
The comparison a == b
must yield a boolean value.
template<typename T>
concept bool ImplicitBoolFn()
{
return requires(T a, T b)
{
{ a == b } -> bool;
};
};
ImplicitBoolVar
and ImplicitBoolFn
have identical semantics, only difference is the first one is implemented as a variable concept, and the second one as a function concept.
Professional Software Developer, doing mostly C++. Connect with Kent on Twitter.