Должен ли "operator! =" Всегда реализовываться через "operator ==" в C ++? - PullRequest
3 голосов
/ 12 января 2011

В настоящее время я проверяю старую кодовую базу C ++ и вижу, что большая часть кода выглядит следующим образом:

bool SomeClass::operator==( const SomeClass& other ) const
{
   return member1 == other.member1 && member2 == other.member2;
}

bool SomeClass::operator!=( const SomeClass& other ) const
{
   return member1 != other.member1 || member2 != other.member2;
}

ясно, что логика сравнения дублируется, и приведенный выше код, вероятно, придется изменить в двух местах, а не вone.

AFAIK Типичный способ реализации operator!= выглядит следующим образом:

bool SomeClass::operator!=( const SomeClass& other ) const
{
    return !( *this == other );
}

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

Существует ли какой-либо разумный случай, когда operator!= должен быть реализован любым другим способом, кроме повторного использования operator== в коде C ++?

Ответы [ 4 ]

9 голосов
/ 12 января 2011

В большинстве случаев семантика a!=b должна быть равна !(a==b).

То же самое относится ко всем остальным операторам: a<b должно быть равно !(a=>b) и !(a==b || a>b), a<=b && !(a==b) и т. Д. И т. П.

Для этой цели boost.operators предлагает несколько потрясающих инструментов для автоматического генерирования операторов в зависимости от других.


Однако, когда вы даете определенную семантику своим операторам (то есть: вы не используете ==, чтобы проверить, являются ли два элемента одинаковыми, но чтобы сделать некоторые причудливые вещи, как STL делает с >> и << ) вы можете захотеть дать им разные реализации.

Эта практика, как правило, не рекомендуется, хотя даже STL и многие библиотеки boost делают это.


РЕДАКТИРОВАТЬ - Небольшое дополнение:

То, что я сказал до сих пор, касается только семантики операторов. Если вы решите, что семантика вашего a!=b должна быть !(a==b), у вас есть два способа реализовать это:

  • путем вызова другого оператора, что происходит, если вы используете boost.operators:
    bool operator!=(a,b) { return !(a==b); }

  • реализация их обоих с нуля.

Первый метод обычно проще в реализации и безопаснее. Наиболее распространенная вещь, которая может оправдать второй вариант, - это оптимизация, хотя, вероятно, она того не стоит: современные компиляторы в большинстве случаев не добавляют никаких издержек (если вы посмотрите на исходный код boost.operators, вы увидите много комментариев о том, как они положитесь на NRVO , чтобы не добавлять накладных расходов, или как их код изменяется, если компилятор не предоставляет NRVO).

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

4 голосов
/ 12 января 2011

ИМХО это разумно и надежно для реализации! = С точки зрения ==. (или наоборот)

3 голосов
/ 12 января 2011

Есть ли разумный случай, когда operator!= должен быть реализован любым другим способом, кроме повторного использования operator== в коде C ++?

Я так не думаю. Но то же самое относится и к другому коду, например, postfix ++ должен всегда быть реализован в виде префикса ++ (за исключением, конечно, нативных типов, где оптимизатор может генерировать более эффективный код, но я верю, что даже тогда аргумент верен) и operator + должен почти всегда быть реализован в терминах operator += (исключение - когда вы работаете с прокси-объектами для задержки выполнения).

Вот почему существует std::relops.

2 голосов
/ 12 января 2011

семантически да (имеется ввиду, что == должно быть логическим дополнением! =), Но практически (кодирование) вам не нужно.

...