Требуйте полный набор операций для концепта
Причина
Простота понимания. Улучшение совместимости. Помощь реализаторам и сопровождающим.
Примечание
Это частный случай общего правила о том, что концепт должен иметь семантический смысл.
Пример (плохой)
template<typename T> concept Subtractable = requires(T a, T b) { a - b; };
Это не имеет семантического смысла. Для того чтобы - было осмысленным и полезным, нужно как минимум +.
Примеры полных наборов:
Arithmetic:+,-,*,/,+=,-=,*=,/=Comparable:<,>,<=,>=,==,!=
Примечание
Это правило применяется независимо от того, используется ли прямая языковая поддержка концептов или нет. Это общее правило проектирования, которое применимо даже к нешаблонному коду:
class Minimal {
// ...
};
bool operator==(const Minimal&, const Minimal&);
bool operator<(const Minimal&, const Minimal&);
Minimal operator+(const Minimal&, const Minimal&);
// других операторов нет
void f(Minimal x, Minimal y)
{
if (!(x == y)) { /* ... */ } // OK
if (x != y) { /* ... */ } // неожиданно! ошибка
while (!(x < y)) { /* ... */ } // OK
while (x >= y) { /* ... */ } // неожиданно! ошибка
x = x + y; // OK
x += y; // неожиданно! ошибка
}
Это минимально, но неожиданно и ограничивает пользователей. Это может быть даже менее эффективным.
Правило поддерживает точку зрения, что концепт должен отражать (математически) согласованный набор операций.
Пример
class Convenient {
// ...
};
bool operator==(const Convenient&, const Convenient&);
bool operator<(const Convenient&, const Convenient&);
// ... и другие операторы сравнения ...
Convenient operator+(const Convenient&, const Convenient&);
// ... и другие арифметические операторы ...
void f(const Convenient& x, const Convenient& y)
{
if (!(x == y)) { /* ... */ } // OK
if (x != y) { /* ... */ } // OK
while (!(x < y)) { /* ... */ } // OK
while (x >= y) { /* ... */ } // OK
x = x + y; // OK
x += y; // OK
}
Определять все операторы может быть немного хлопотно, но несложно. В идеале это правило должно поддерживаться языком, предоставляя операторы сравнения по умолчанию.
Контроль
Да, std::string является «нечётным», но уже слишком поздно это менять.
- Помечать классы, поддерживающие «нечётные» подмножества набора операторов, например
==без!=или+без-.