Чем трехсторонний оператор сравнения отличается от вычитания?
Там новый оператор сравнения <=>
в С ++20. Однако я думаю, что в большинстве случаев простое вычитание работает хорошо:
int my_strcmp(const char *a, const char *b) {
while (*a == *b && *a != 0 && *b != 0) {
a++, b++;
}
// Version 1
return *a - *b;
// Version 2
return *a <=> *b;
// Version 3
return ((*a > *b) - (*a < *b));
}
Они имеют одинаковый эффект. Я не могу понять разницу.
3 ответа
Оператор решает проблему с числовым переполнением, которое вы получаете с вычитанием: если вы вычтите большое положительное число из отрицания, которое близко к INT_MIN
, вы получите номер, который не может быть представлен как int
таким образом вызывая неопределенное поведение.
Хотя версия 3 свободна от этой проблемы, ей совершенно не хватает читабельности: потребуется время, чтобы понять тот, кто никогда раньше не видел этот трюк. <=>
Оператор также исправляет проблему читабельности.
Это только одна проблема, решаемая новым оператором. В разделе 2.2.3 " Сравнительного документа Херба Саттера" говорится об использовании <=>
с другими типами данных языка, где вычитание может привести к противоречивым результатам.
Вот некоторые случаи, когда вычитание не будет работать для:
unsigned
типы.- Операнды, вызывающие целочисленное переполнение.
- Пользовательские типы, которые не определяют
operator -
(возможно, потому что это не имеет смысла - можно определить порядок, не определяя понятие расстояния).
Я подозреваю, что этот список не является исчерпывающим.
Конечно, можно найти обходные пути как минимум для № 1 и № 2. Но намерение operator <=>
это заключить в капсулу это уродство.
Здесь есть несколько значимых ответов о разнице, но Херб Саттер в своей статье специально говорит:
<=> для разработчиков типов: пользовательский код (включая общий код) вне реализации оператора<=> почти никогда не должен вызывать <=> напрямую (что уже было обнаружено в качестве хорошей практики в других языках);
Таким образом, даже если бы не было никакой разницы, смысл оператора в другом: помочь авторам классов генерировать операторы сравнения.
Основное различие между оператором вычитания и оператором "космического корабля" (согласно предложению Саттера) состоит в том, что перегрузка operator-
дает вам оператор вычитания, тогда как перегрузка operator<=>
:
- дает вам 6 операторов сравнения ядра (даже если вы объявите оператор как
default
: нет кода для записи!); - объявляет, сопоставим ли ваш класс, можно ли сортировать, и является ли порядок полным или частичным (сильный / слабый в предложении Саттера);
- допускает гетерогенные сравнения: вы можете перегрузить его, чтобы сравнить ваш класс с любым другим типом.
Другие различия в возвращаемом значении: operator<=>
вернет enum
класса указывает, является ли тип сортируемым и является ли сортировка сильной или слабой. Возвращаемое значение будет преобразовано в -1, 0 или 1 (хотя Саттер оставляет место для возвращаемого типа, чтобы также указать расстояние, как strcmp
делает). В любом случае, предполагая возвращаемое значение -1, 0, 1, мы наконец получим истинную функцию signum в C++! (signum(x) == x<=>0
)