Это код из стандартного remove
кода библиотеки C ++ . Почему неравенство проверяется if (!(*first == val))
вместо if (*first != val)
?
template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val)
{
ForwardIterator result = first;
while (first!=last) {
if (!(*first == val)) {
*result = *first;
++result;
}
++first;
}
return result;
}
operator!=
. Просто используйтеoperator==
реализацию:bool operator!=(const Foo& other) { return !(*this == other); }
operator==
как ожидается, будет использовано здесь ...const
в моем предыдущем комментарии также должен быть пример, но вы поняли. (Слишком поздно для редактирования)EqualityComparable
которую Хюркил упомянул в своем ответе .Ответы:
Потому что это означает, что единственным требованием к T является реализация
operator==
. Вы могли бы потребовать, чтобы T имел,operator!=
но общая идея здесь состоит в том, что вы должны наложить как можно меньше нагрузки на пользователя шаблона, а другие шаблоны действительно нуждаютсяoperator==
.источник
x != y
не определяется так же, как!(x == y)
. Что если эти операторы возвращают дерево разбора встроенного DSL?!=
, поддерживается ли он (неправильно вернул бы true - даже еслиoperator==
не поддерживается!). Я также волнуюсь, что это приведет к тому, что некоторые применения!=
станут неоднозначными.Большинство функций в STL работают только с
operator<
илиoperator==
. Это требует от пользователя только реализации этих двух операторов (или иногда хотя бы одного из них). Напримерstd::set
используетoperator<
(точнее,std::less
который вызываетoperator<
по умолчанию), а неoperator>
управлять порядком.remove
Шаблон в вашем примере подобный случай - он использует толькоoperator==
и неoperator!=
такoperator!=
не должны быть определены.источник
operator<
напрямую, а вместо этого используютstd::less
, что, в свою очередь, по умолчаниюoperator<
.std::set
, действительно используютoperator<
напрямую. Странно ...std::equal_to
, они используют,operator==
как отмечено в вопросе. Ситуация сstd::less
аналогична. Ну, может бытьstd::set
, не лучший пример.std::equal_to
иstd::less
используются в качестве параметров шаблона по умолчанию, где компаратор берется в качестве параметра.operator==
иoperator<
используются непосредственно там, где тип требуется для удовлетворения сопоставимого равенства и строгого слабого порядка соответственно, например, итераторы и итераторы с произвольным доступом.Неправильно. Это не C ++ стандартной библиотеки кода. Это одна из возможных внутренних реализаций стандартной библиотечной функции C ++ . Стандарт C ++ не предписывает фактический код; он предопределяет функциональные прототипы и требуемое поведение.
remove
remove
Другими словами: с точки зрения языка, код, который вы видите , не существует . Это может быть из какого-то заголовочного файла, который поставляется с реализацией стандартной библиотеки вашего компилятора. Обратите внимание, что стандарт C ++ даже не требует, чтобы эти заголовочные файлы существовали. Файлы - это просто удобный способ для разработчиков компилятора удовлетворить требования для такой строки
#include <algorithm>
(например, сделатьstd::remove
доступными и другие функции).Потому
operator==
что требуется только функция.Когда речь заходит о перегрузке операторов для пользовательских типов, язык позволяет вам делать разные странные вещи. Вы могли бы очень хорошо создать класс, который перегружен,
operator==
но не перегруженoperator!=
. Или даже хуже: вы могли бы перегружать,operator!=
но делать это совершенно не связанными вещами.Рассмотрим этот пример:
Если
std::remove
использоватьoperator!=
, то результат будет совсем другим.источник
a==b
и другое, иa!=b
вернуть false. Хотя не всегда может быть ясно, будет ли такая ситуация более осмысленно рассматриваться как «равная» или «не равная», функция, которая определяет равенство исключительно в терминах оператора «==», должна рассматривать их как «неравные». ", независимо от того, какое поведение имело бы больше смысла [если бы у меня были мои детекторы, все типы должны были бы обеспечивать логически приводящие операторы" == "и"! = ", ведущие себя согласованно, но тот факт, что IEEE-754 требует нарушенного равенства операторы затруднят такое ожидание.==
и!=
ведет себя последовательно, хотя я всегда думал, что все шесть отношений должны оцениваться,false
когда хотя бы один операнд естьNaN
.Несколько хороших ответов здесь. Я просто хотел добавить небольшую заметку.
Как и все хорошие библиотеки, стандартная библиотека разработана с учетом (как минимум) двух очень важных принципов:
Возложите на пользователей вашей библиотеки наименьшую ответственность, которой вы можете избежать. Частично это связано с предоставлением им минимального объема работы при использовании вашего интерфейса. (например, определение как можно меньшего числа операторов). Другая часть этого связана с тем, чтобы не удивлять их или требовать, чтобы они проверяли коды ошибок (поэтому оставляйте интерфейсы согласованными и создавайте исключения,
<stdexcept>
когда что-то идет не так).Устранить всю логическую избыточность . Все сравнения могут быть выведены просто из
operator<
, так зачем требовать, чтобы пользователи определяли других? например:(a> b) эквивалентно (b <a)
(a> = b) эквивалентно! (a <b)
(a == b) эквивалентно! ((a <b) || (b <a))
и так далее.
Конечно, в этой заметке можно спросить, почему
unordered_map
требуетсяoperator==
(по крайней мере, по умолчанию), а неoperator<
. Ответ в том, что в хеш-таблице единственное сравнение, которое нам когда-либо требуется, - это сравнение на равенство. Таким образом, логически непротиворечиво (т. Е. Имеет больше смысла для пользователя библиотеки) требовать от него определения оператора равенства. Требованиеoperator<
будет сбивать с толку, потому что не сразу понятно, зачем вам это нужно.источник
operator==
(иhash
).!(a==b)
. Поскольку неотраженная перегрузка операторов может легко привести к тому, что программа на C ++ полностью испортится (плюс, заставьте программиста сходить с ума, потому что отладка его кода может стать невыполнимой задачей, поскольку найти виновника конкретной ошибки напоминает одиссею).!((a < b) || (b < a))
использует на одного оператора меньше bool, так что это, вероятно, быстрееEqualityComparable
Понятие только требует , чтобыoperator==
определить.Следовательно, любая функция, которая утверждает, что работает с типами, удовлетворяющими,
EqualityComparable
не может полагаться на существованиеoperator!=
для объектов этого типа. (если нет дополнительных требований, предполагающих наличиеoperator!=
).источник
Из Boost FAQ: источник
Зная, что требовать
==
внедрения - это бремя , вы никогда не захотите создавать дополнительное бремя, требуя также и!=
реализации.Лично для меня это L-часть SOLID (объектно-ориентированное проектирование) - принцип подстановки Лискова: «объекты в программе должны заменяться экземплярами их подтипов без изменения правильности этой программы». В этом случае это оператор ! = , Который я могу заменить на == и логическое обратное в логической логике.
источник