2016-06-11 2 views
3

Я слышал, что C++ позволяет переопределять как operator==, так и operator!=, потому что в некоторых случаях a != b может быть реализован более эффективно, чем !(a == b).Когда имеет смысл иметь отдельные реализации для оператора == и оператора! =?

Я подумал об этом и не могу представить случай, когда это правда.

Каковы некоторые примеры, когда имеет смысл, по производительности или другому, иметь отдельные реализации для operator== и operator!=?

+2

Вам не нужно знать. Достаточно сказать, что там могут возникнуть сценарии, в которых у вас есть очень очевидное условие неравенства и гораздо менее очевидное условие равенства. C++ не собирается * колпачок * вы и заставляете вас определять неравенство * только * в терминах равенства или наоборот. – meagar

ответ

4

Первый пример, который приходит на ум, - это реализации, аналогичные значению NULL для SQL. При этом, сравнивая два объекта —, каждый из которых имеет значение NULL —, не означает, что они равны. Только если оба не являются NULL, имеет смысл возвращать равенство.

+1

Мне непонятно, что вы говорите. Если они оба являются NULL, что должно «operator ==» возвращаться? Похоже, вы говорите, что он должен вернуть ложь. Это нормально. Но говорите ли вы, что 'operator! =' Также должен возвращать false? Значит, они не равны, но они не * не * равны? –

+1

Возможно, это поможет https://en.wikipedia.org/wiki/Null_%28SQL%29 –

0

В очень простых ситуациях достаточной идиомой «осуществлять равенство в терминах неравенства» (или наоборот). На x86 cmp instruction используется как для равенства, так и для неравенства. Рассмотрим следующий пример:

struct Foo 
{ 
    bool operator==(const Foo& rhs) 
    { 
    return val == rhs.val; 
    } 

    bool operator!=(const Foo& rhs) 
    { 
    return val != rhs.val; 
    } 

    int val; 
}; 

Foo a{20}; 
Foo b{40}; 
Foo c{20}; 

int main() 
{ 
    (void)(a == b); 
    (void)(a == c); 
    (void)(a != b); 
    (void)(a != c); 
} 

Это будет компилировать в одинаковой сборки, без sete против setne. Люди могут разделить волосы и смутные утверждения о предсказании ветвей, конвейерах, кэше процессора и т. Д. Но они действительно просто пустые заявления.

В сложных ситуациях может быть заманчивым, чтобы дать различную семантику для operator== и operator!=, но я не согласен с этим принципом:

  • Вы нарушающего ожидания пользователя, что эти два оператора обратные друг другу. Например, существует ли разница между !(a == b) или a != b? Вы легко попадаете в ловушку других языков, таких как PHP и Javascript, где равенство - это особый тип ада.

  • Скрытие сложных объектов за счет перегрузки оператора и итераторов может сильно ухудшить производительность. Люди используют эти функции, исходя из предположения, что они дешевы (и в большинстве случаев они есть). Дорогой «итератор» или «равенство» очень трудно использовать правильно.

«Когда это имеет смысл», скорее всего, это вопрос, отвечающий требованиям бизнеса, чем правильный дизайн, к сожалению.

3

Если вы хотите иметь правило, 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 != здесь.

Смежные вопросы