Чем трехсторонний оператор сравнения отличается от вычитания?

Там новый оператор сравнения <=> в С ++ 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));
}

Они имеют одинаковый эффект. Я не могу понять разницу.

43

Решение

Оператор решает проблему с числовым переполнением, которое вы получаете с вычитанием: если вы вычтите большое положительное число из отрицания, которое близко к INT_MIN, вы получите номер, который не может быть представлен как intтаким образом вызывая неопределенное поведение.

Хотя версия 3 свободна от этой проблемы, ей совершенно не хватает читабельности: потребуется время, чтобы понять тот, кто никогда раньше не видел этот трюк. <=> Оператор также исправляет проблему читабельности.

Это только одна проблема, решаемая новым оператором. Раздел 2.2.3 из Херб Саттерс Последовательное сравнение бумага говорит об использовании <=> с другими типами данных языка, где вычитание может привести к противоречивым результатам.

49

Другие решения

Вот некоторые случаи, когда вычитание не будет работать для:

  1. unsigned типы.
  2. Операнды, вызывающие целочисленное переполнение.
  3. Пользовательские типы, которые не определяют operator - (возможно, потому что это не имеет смысла — можно определить порядок, не определяя понятие расстояния).

Я подозреваю, что этот список не является исчерпывающим.

Конечно, можно найти обходные пути как минимум для № 1 и № 2. Но намерение operator <=> это заключить в капсулу это уродство.

39

Здесь есть несколько значимых ответов о разнице, но Херб Саттер в его бумага конкретно говорит:

<=> для разработчиков типов: код пользователя (включая универсальный код) вне реализации оператора<=> почти никогда не должен вызывать <=> напрямую (как уже было обнаружено в качестве хорошей практики на других языках);

Таким образом, даже если бы не было никакой разницы, смысл оператора в другом: помочь авторам классов генерировать операторы сравнения.

Основное различие между оператором вычитания и оператором «космического корабля» (согласно предложению Саттера) состоит в том, что перегрузка operator- дает вам оператор вычитания, тогда как перегрузка operator<=>:

  • дает вам 6 операторов сравнения ядра (даже если вы объявите оператор как default: нет кода для записи!);
  • объявляет, сопоставим ли ваш класс, можно ли сортировать, и является ли порядок полным или частичным (сильный / слабый в предложении Саттера);
  • допускает гетерогенные сравнения: вы можете перегрузить его, чтобы сравнить ваш класс с любым другим типом.

Другие различия в возвращаемом значении: operator<=> вернет enum класса указывает, является ли тип сортируемым и является ли сортировка сильной или слабой. Возвращаемое значение будет преобразовано в -1, 0 или 1 (хотя Саттер оставляет место для возвращаемого типа, чтобы также указать расстояние, как strcmp делает). В любом случае, принимая значение -1, 0, 1, мы, наконец, получим настоящая функция signum в C ++! (signum(x) == x<=>0)

14
По вопросам рекламы [email protected]