Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

Оператор эквивалентности <=>

#c++ #операторы #c++20

Увидел недавно оператор <=> в чужом коде и испытал культурный шок. Что за зверь,
что он делает и когда использовать?

#include 
#include 


int main() {
    int a, b = a = 42;

    std::cout << (a <=> b == 0);
}

    


Ответы

Ответ 1

Такой оператор известен как "spaceship operator" или космический корабль или оператор трехстороннего сравнения (так его официально называют), чаще всего я слышу первый вариант. Я этот оператор первый раз увидел на Perl и вроде как это был первый язык который использовал его, после чего он начал появляться в Ruby, PHP, C++ и т.д. Этот оператор предназначен для сравнения двух выражений или значений. Запомнить как он работает, очень просто: Возвращается целочисленное значение -1, 0 или 1 если a, соответственно, меньше, равно или больше чем b. Все просто и очевидно, минус значит меньше, 0 значит нет разницы, 1 больше. Со стороны программного кода это эквивалент: if ab return 1 else return 0 end Набор таких возвращаемых значений уже давно известен, примерно с таким же успехом для строк работает функция strcmp или memcmp. Очень удобно использовать данный оператор для реализаций всяких сортировок, ведь если писать какую-нибудь функцию сравнения и сортировки числового массива нужно 3 значения (больше, меньше, равно), так как значений bool (0,1) недостаточно.

Ответ 2

Если вы когда либо писали операторы сравнения в более-менее тяжелых C++ классах, то вы, наверное, замечали, что вся идея построения системы сравнений вокруг классических операторов <, >, == и т.д. и/или вокруг соотношения "less" ("меньше"), на который опираются упорядочивающие алгоритмы стандартной библиотеки неудобна и дико неэффективна. Не существует приемлемого/эффективного способа реализации упорядочивающих соотношений для составных объектов на основе существующих соотношений для их индивидуальных компонентов. Например, для класса class Composite { Type1 a; Type2 b; Type3 c; }; лексикографическое сравнение < будет выглядеть примерно так bool operator <(const Composite &lhs, const Composite &rhs) { if (lhs.a != rhs.a) return lhs.a < rhs.a; if (lhs.b != rhs.b) return lhs.b < rhs.b; return lhs.c < rhs.c; } Это, разумеется, катастрофически плохо, ибо такой вариант на некотором шаге выполняет фактически одно и то же сравнение два раза. К примеру, сначала делается lhs.a != rhs.a, а затем lhs.a < rhs.a, то по сути является повторным выполнением одной и той же (возможно тяжелой) операции. Чтобы решить эту проблему, в С++20 предложили новую парадигму реализации сравнений: в качестве основы выступают "трехсторонние" ("3-way") сравнения, хорошо знакомые нам еще из C. Теперь фундаментальным примитивом упорядочивающего сравнения для каждого типа данных будет оператор <=>, выполняющий трехстороннее сравнение. Все остальные виды сравнения будут неявно генерироваться на основе результата оператора <=>. Например, на основе оператора <=> вышеприведенный скетч кода может быть переписан так bool operator <(const Composite &lhs, const Composite &rhs) { if (auto cmp = lhs.a <=> rhs.a; cmp != 0) return cmp < 0; if (auto cmp = lhs.b <=> rhs.b; cmp != 0) return cmp < 0; if (auto cmp = lhs.c <=> rhs.c; cmp != 0) return cmp < 0; return false; } (Пример приведен в иллюстративных целях. На самом деле правильнее будет реализовать именно и только оператор <=> для класса Composite и дать компилятору сгенерировать оператор < на его основе.) Так что ответ на ваш вопрос про "когда использовать": никогда и всегда. В коде верхнего уровня он почти никогда не нужен. В вашем примере нет никакого повода использовать <=> вместо обычного ==. А вот в качестве лежащей под всем этим основы для реализации операторов сравнения он нужен почти всегда. Без него вы просто не сможете построить приемлемой реализации лексикографического сравнения для составного объекта. В этой роли большинство из нас уже давно руками выписывали аналог этого оператора в виде какой-то функции. А теперь эта практика будет закреплена на уровне языка. Также в стандартной библиотеке С++20 появится вспомогательная функция std::compare_3way, реализующая трехсторонние сравнения на базе обычных сравнений.

Ответ 3

Это называется трехсторонним оператором сравнения. Согласно предложению P0515: Появился новый трехсторонний оператор сравнения <=>. Выражение a <=> b возвращает объект, который сравнивает <0 a="" b=""> 0, если a> b, и сравнивает == 0, если a и b равны / эквивалентны. Чтобы написать все сравнения для вашего типа, просто напишите оператор <=>, который возвращает соответствующий тип категории: Верните _ordering, если ваш тип естественным образом поддерживает <, и мы будем эффективно генерировать <,>, <=,> =, == и! =; в противном случае верните _equality, и мы будем эффективно генерировать == и! =. Возвращает значение strong, если для вашего типа a == b подразумевает f (a) == f (b) (подстановочность, где f читает только состояние сравнения, доступное с использованием не частного интерфейса const), в противном случае возвращает значение слабое. Совпадение говорит: Выражения оператора трехстороннего сравнения имеют вид lhs <=> rhs (1) Выражение возвращает объект, который сравнивает <0 lhs="" rhs=""> 0, если lhs> rhs и сравнивает == 0, если lhs и rhs равны / эквивалентны.

Комментариев нет:

Отправить комментарий