Avoid "concepts" without meaningful semantics
Reason
Concepts are meant to express semantic notions, such as "a number", "a range" of elements, and "totally ordered." Simple constraints, such as "has a + operator" and "has a > operator" cannot be meaningfully specified in isolation and should be used only as building blocks for meaningful concepts, rather than in user code.
Example, bad
template<typename T>
// bad; insufficient
concept Addable = requires(T a, T b) { a + b; };
template<Addable N>
auto algo(const N& a, const N& b) // use two numbers
{
// ...
return a + b;
}
int x = 7;
int y = 9;
auto z = algo(x, y); // z = 16
string xx = "7";
string yy = "9";
auto zz = algo(xx, yy); // zz = "79"
Maybe the concatenation was expected. More likely, it was an accident. Defining minus equivalently would give dramatically different sets of accepted types. This Addable violates the mathematical rule that addition is supposed to be commutative: a+b == b+a.
Note
The ability to specify meaningful semantics is a defining characteristic of a true concept, as opposed to a syntactic constraint.
Example
template<typename T>
// The operators +, -, *, and / for a number are assumed to follow the usual mathematical rules
concept Number = requires(T a, T b) { a + b; a - b; a * b; a / b; };
template<Number N>
auto algo(const N& a, const N& b)
{
// ...
return a + b;
}
int x = 7;
int y = 9;
auto z = algo(x, y); // z = 16
string xx = "7";
string yy = "9";
auto zz = algo(xx, yy); // error: string is not a Number
Note
Concepts with multiple operations have far lower chance of accidentally matching a type than a single-operation concept.
Enforcement
- Flag single-operation
conceptswhen used outside the definition of otherconcepts. - Flag uses of
enable_ifthat appear to simulate single-operationconcepts.