Если вы хотите иметь правило, a == b
возвращает истину, когда именно a != b
возвращает ложь, то на самом деле, нет никаких оснований, чтобы иметь две реализации, если вы надеетесь, чтобы оптимизировать выход один !
каким-то образом. (Что очень редко может изменить ситуацию, а лучше сделать оптимизатором.)
Однако C++ обычно не предполагает, что оператор перегружает подчиненные правила, подобные этому.
Например, вы могли бы подумать также, что, если вам нужно только перегружать operator <
, а затем получить operator >
, оператор <=
, оператор >=
и оператор ==
бесплатно.Поскольку все они могут быть определены в терминах operator <
, если вы предполагаете, что он возвращает bool, и отношение должно быть частичным порядком.
Но в некоторых случаях операторы также используются для более сложного синтаксиса и семантики. Если бы эти типы «тождеств» были наложены, это сделало бы некоторые вещи, например, шаблоны экспрессии невозможными.
C++ не налагает на вас никаких «идентичностей». Вы можете дать операторам любой смысл, который вы чувствуете, к лучшему или худшему.
Итак, я думаю, что вы слышали, может быть, неправильное представление. Причина, по которой у вас есть эта свобода, заключается не в том, чтобы предоставить больше возможностей для «эффективности», это позволит вам дать операторам смысл, который вы хотите, когда они используются с вашими пользовательскими классами.
Для полноты, вот пример того, о чем я говорю.
namespace expression_builder {
struct arg {
bool operator()(bool input) const {
return input;
}
};
template <typename E>
struct negate {
E e;
bool operator()(bool input) const {
return !e(input);
}
};
template <typename E1, typename E2>
struct equals {
E1 e1;
E2 e2;
bool operator()(bool input) const {
return e1(input) == e2(input);
}
};
template <typename E1, typename E2>
struct not_equals {
E1 e1;
E2 e2;
bool operator()(bool input) const {
return e1(input) != e2(input);
}
};
// Operator overloads
template <typename T>
auto operator!(T t) -> negate<T> {
return {t};
}
template <typename T1, T2>
auto operator==(T1 t1, T2 t2) -> equals<T1, T2> {
return {t1, t2};
}
template <typename T1, T2>
auto operator!=(T1 t1, T2 t2) -> not_equals<T1, T2> {
return {t1, t2};
}
} // end namespace expression_builder
int main() {
using expression_builder::arg;
auto my_functor = (arg == (arg != (!arg)));
bool test1 = my_functor(true);
bool test2 = my_functor(false);
}
В этом коде оператор перегрузки используется, чтобы позволить вам построить функциональные объекты для выполнения простых логических функций. Процесс построения функции происходит полностью во время компиляции, поэтому полученный код очень эффективен. Люди используют это с гораздо более сложными примерами, чтобы очень эффективно выполнять определенные виды функционального программирования на C++. И очень важно, что operator ==
имеет совсем другую реализацию от operator !=
здесь.
Вам не нужно знать. Достаточно сказать, что там могут возникнуть сценарии, в которых у вас есть очень очевидное условие неравенства и гораздо менее очевидное условие равенства. C++ не собирается * колпачок * вы и заставляете вас определять неравенство * только * в терминах равенства или наоборот. – meagar