To jest kod ze standardowego remove
kodu biblioteki C ++ . Dlaczego nierówność jest testowana jako if (!(*first == val))
zamiast 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!=
. Po prostu skorzystaj zoperator==
implementacji:bool operator!=(const Foo& other) { return !(*this == other); }
operator==
oczekuje się, że zostanie tutaj użyty ...const
przykładzie w moim poprzednim komentarzu powinno być również , ale o co chodzi. (Za późno, aby to edytować)EqualityComparable
którym Hurkyl wspomniał w swojej odpowiedzi .Odpowiedzi:
Ponieważ oznacza to, że jedynym wymaganiem na T jest implementacja
operator==
. Możesz wymagać od T, aby mieć,operator!=
ale ogólna idea jest taka, że powinieneś obciążać użytkownika szablonu jak najmniejszym, a inne szablony wymagająoperator==
.źródło
x != y
nie jest zdefiniowany jako taki sam jak!(x == y)
. Co się stanie, jeśli te operatory zwrócą drzewo analizy osadzonego DSL?!=
jest obsługiwana (niepoprawnie zwróci wartość true - nawet jeślioperator==
nie jest obsługiwana!). Martwię się również, że spowoduje to!=
niejednoznaczność niektórych zastosowań .Większość funkcji w STL działa tylko z
operator<
luboperator==
. Wymaga to od użytkownika tylko zaimplementowania tych dwóch operatorów (lub czasami przynajmniej jednego z nich). Na przykładstd::set
używaoperator<
(a dokładniej,std::less
która wywołujeoperator<
domyślnie), a nieoperator>
do zarządzania kolejnością.remove
Szablon w przykładzie jest podobny przypadek - używa tylkooperator==
i nieoperator!=
takoperator!=
nie musi być zdefiniowana.źródło
operator<
bezpośrednio, ale zamiast tego używająstd::less
, co z kolei domyślnieoperator<
.std::set
, Rzeczywiście używająoperator<
bezpośrednio. Dziwne ...std::equal_to
, używająoperator==
jak wskazano w pytaniu. Sytuacjastd::less
jest podobna. Cóż, możestd::set
nie jest to najlepszy przykład.std::equal_to
istd::less
są używane jako domyślne parametry szablonu, w których jako parametr przyjmuje się komparator.operator==
ioperator<
są używane bezpośrednio tam, gdzie typ jest wymagany do spełnienia równości, odpowiednio, porównywalnej i ścisłej słabej kolejności, np. iteratory i iteratory o swobodnym dostępie.Źle. To nie jest standardowy
remove
kod biblioteki C ++ . Jest to jedna z możliwych implementacji wewnętrznej biblioteki standardowej C ++remove
funkcji . Standard C ++ nie określa faktycznego kodu; zawiera prototypy funkcji i wymagane zachowania.Innymi słowy: ze ścisłego punktu widzenia języka kod, który widzisz , nie istnieje . Może pochodzić z jakiegoś pliku nagłówkowego, który jest dostarczany z implementacją biblioteki standardów kompilatora. Zauważ, że standard C ++ nie wymaga nawet istnienia tych plików nagłówkowych . Pliki są po prostu wygodnym sposobem dla implementujących kompilatory, aby spełnić wymagania dla linii
#include <algorithm>
(tj.std::remove
Udostępnianie i inne funkcje).Ponieważ
operator==
wymaga tego tylko funkcja.Jeśli chodzi o przeciążanie operatorów dla typów niestandardowych, język pozwala robić różne dziwne rzeczy. Możesz bardzo dobrze stworzyć klasę, która ma przeciążoną,
operator==
ale nie przeciążonąoperator!=
. Lub nawet gorzej: możesz przeciążaćoperator!=
ale sprawić, by robił zupełnie niezwiązane rzeczy.Rozważmy ten przykład:
Jeśli zostanie
std::remove
użytyoperator!=
, wynik byłby zupełnie inny.źródło
a==b
ia!=b
zwrócenia fałszu. Chociaż nie zawsze może być jasne, czy taka sytuacja byłaby bardziej sensownie traktowana jako „równa” czy „nierówna”, funkcja, która definiuje równość wyłącznie na podstawie operatora „==”, musi traktować je jako „nierówne” ", bez względu na to, które zachowanie miałoby więcej sensu [gdybym miał swoje wybory, od wszystkich typów należałoby oczekiwać, że operatory logiczne" == "i"! = "będą działały konsekwentnie, ale fakt, że IEEE-754 nakazuje złamanie równości operatorzy utrudnialiby takie oczekiwanie].==
i!=
zachowuje się konsekwentnie, chociaż zawsze uważałem, że wszystkie sześć relacji powinno się oceniać,false
gdy co najmniej jeden operand jestNaN
.Kilka dobrych odpowiedzi. Chciałem tylko dodać małą notatkę.
Podobnie jak wszystkie dobre biblioteki, biblioteka standardowa została zaprojektowana z uwzględnieniem (co najmniej) dwóch bardzo ważnych zasad:
Połóż najmniejszą odpowiedzialność na użytkownikach swojej biblioteki, z którą możesz uciec. Częściowo wiąże się to z poświęceniem im najmniejszej ilości pracy podczas korzystania z interfejsu. (np. zdefiniowanie jak najmniejszej liczby operatorów). Druga część polega na tym, że nie zaskakuje ich ani nie wymaga od nich sprawdzania kodów błędów (więc zachowaj spójność interfejsów i zgłaszaj wyjątki,
<stdexcept>
gdy coś pójdzie nie tak).Wyeliminuj całą logiczną nadmiarowość . Wszystkie porównania można wyprowadzić po prostu z
operator<
, więc po co żądać, aby użytkownicy definiowali innych? na przykład:(a> b) jest równoważne (b <a)
(a> = b) jest równoważne! (a <b)
(a == b) jest równoważne! ((a <b) || (b <a))
i tak dalej.
Oczywiście w tej notatce można zapytać, dlaczego
unordered_map
wymagaoperator==
(przynajmniej domyślnie), a nieoperator<
. Odpowiedź jest taka, że w tabeli skrótów jedyne porównanie, jakiego kiedykolwiek potrzebujemy, dotyczy równości. Dlatego jest bardziej logicznie spójne (tj. Ma większy sens dla użytkownika biblioteki), aby wymagać od niego zdefiniowania operatora równości. Wymaganieoperator<
byłoby mylące, ponieważ nie jest od razu oczywiste, dlaczego go potrzebujesz.źródło
operator==
(ihash
).!(a==b)
. Ponieważ niezrefleksowane przeciążenie operatorów może łatwo spowodować całkowite zepsucie programu C ++ (plus, sprawić, że programista oszaleje, ponieważ debugowanie jego kodu może stać się misją niemożliwą, ponieważ znalezienie sprawcy konkretnego błędu przypomina odyseję).!((a < b) || (b < a))
używa jednego operatora bool mniej, więc prawdopodobnie jest szybszyEqualityComparable
Pojęcie tylko wymaga,operator==
być zdefiniowane.W konsekwencji żadna funkcja, która twierdzi, że działa z typami spełniającymi,
EqualityComparable
nie może polegać na istnieniuoperator!=
obiektów for tego typu. (chyba że istnieją dodatkowe wymagania, które implikują istnienieoperator!=
).źródło
Od Często zadawane pytania dotyczące Boost: źródło
Wiedząc, że wymaganie
==
implementacji jest obciążeniem , nigdy nie chcesz stwarzać dodatkowego obciążenia wymaganiem!=
implementacji.Dla mnie osobiście chodzi o SOLID (projektowanie obiektowe) L część - zasada podstawienia Liskova: „obiekty w programie powinny być zastępowalne instancjami ich podtypów bez zmiany poprawności tego programu”. W tym przypadku jest to operator ! = , Który mogę zastąpić znakiem == i odwrotnością boolowską w logice boolowskiej.
źródło