There are two kinds of parameterized constraints, one to check if an expression between two operands are allowed, and one for checking a constant value. It’s not legal to put a constraint on non-constant values.
template<typename T>
concept bool ParameterizedConstraint = requires (T a, T b)
{
a == b;
a != b;
};
The concept ParameterizedConstraint
checks if both operations a == b
and a != b
are defined and allowed. It does not check the values of a
and b
.
The following example contains one subtle mistake. Hint: It will build for any type of T
.
template<typename T>
concept bool ParameterizedConstraint2 = requires (T a, T b)
{
sizeof(a) == 4;
a == b;
a != b;
};
The subtle mistake is sizeof(a) == 4;
. The requirement for a parameterized expression is that both operands are constant. Both sizeof(a)
and 4
are constants. What actually is checked is if the equals operator ==
is defined between two integer types. It does not check if the size of a
is 4 bytes!
template<typename T>
concept bool ParameterizedConstraint3 = requires (T a, T b)
{
requires sizeof(a) == 4;
a == b;
a != b;
};
To check constant values in a requires section, the requires
keyword is required. To check for the size, add requires
in front of the expression, requires sizeof(a) == 4;
.
What is the difference between the following two concepts?
template<typename T>
concept bool ParameterizedConstraint4 =
requires
{
4 == 5;
};
template<typename T>
concept bool ParameterizedConstraint5 =
requires
{
requires 4 == 5;
};
The answer is left as an exercise for the reader.
Professional Software Developer, doing mostly C++. Connect with Kent on Twitter.