Parameterized constraints

By , last updated November 14, 2019

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.