296

私は C++ での演算子のオーバーロードについて学んでい==ます!=。これは、ユーザー定義型用にカスタマイズできる特別な関数にすぎません。しかし、私の懸念は、なぜ2 つの別個の定義が必要なのかということです。a == bが true の場合、 thena != bは自動的に false になり、その逆も成り立つと考えました。定義上、a != bはであるため、他の可能性はありません!(a == b)。そして、これが真実でない状況は想像できませんでした。しかし、私の想像力は限られているのでしょうか、それとも私は何かを知らないのでしょうか?

一方を他方の観点から定義できることは知っていますが、これは私が求めていることではありません。また、オブジェクトを値または ID で比較することの違いについても質問していません。または、2 つのオブジェクトが同時に等しくなる可能性と等しくない可能性があるかどうか (これは絶対にオプションではありません! これらは相互に排他的です)。私が尋ねているのはこれです:

2 つのオブジェクトが等しいことについて質問するのは理にかなっていますが、それらが等しくないことについて質問することは意味がないという状況はありますか? (ユーザーの観点から、または実装者の観点から)

そのような可能性がない場合、一体なぜ C++ でこれら 2 つの演算子が 2 つの異なる関数として定義されているのでしょうか?

4

15 に答える 15

274

以外の何かを返すときのように、言語が自動的に書き換えるのを望まないでしょう。そして、それを行う理由がいくつかあります。a != b!(a == b)a == bbool

式ビルダー オブジェクトがある場合があります。ここでa == bは、比較を実行せず、比較を実行することを意図していませんが、 を表す式ノードを構築するだけa == bです。

a == b直接比較を実行することは意図されていませんが、後で実際に比較を実行するために暗黙的または明示的に変換できる何らかの種類の値を返しますlazy<bool>bool評価前に式を完全に最適化できるように、式ビルダー オブジェクトと組み合わせることができます。

optional<T>オプションの変数tuを指定すると、 を許可したいカスタム テンプレート クラスがいくつかあるかもしれませんがt == u、 を返すようにしoptional<bool>ます。

思いもよらなかったことがもっとあるはずです。これらの例では、操作a == ba != bdo はどちらも意味がありますが、それでもa != bと同じではない!(a == b)ため、別個の定義が必要です。

于 2016-06-13T22:41:13.057 に答える
45

と が必ずしも正反対である(a == b)(a != b)限らない、非常に確立された規則がいくつかあります。特に、SQL では、NULL と比較すると、真でも偽でもなく、NULL が返されます。

直観的ではないため、可能な限り新しい例を作成することはおそらく良い考えではありませんが、既存の規則をモデル化しようとしている場合は、オペレーターをそのために「正しく」動作させるオプションがあると便利です環境。

于 2016-06-14T05:54:10.783 に答える
25

私はあなたの質問の 2 番目の部分、つまり次の部分だけに答えます。

そのような可能性がない場合、一体なぜ C++ でこれら 2 つの演算子が 2 つの異なる関数として定義されているのでしょうか?

開発者が両方をオーバーロードできるようにすることが理にかなっている理由の 1 つは、パフォーマンスです。==と の両方を実装することで、最適化を可能にすることができます!=。それならx != y今より安いかもしれません!(x == y)。一部のコンパイラは最適化できる場合がありますが、多くの分岐が含まれる複雑なオブジェクトがある場合は特にそうではありません。

開発者が法則と数学的概念を非常に真剣に考えている Haskell でも、ここでわかるように、==との両方をオーバーロードすることが許可されています ( http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude .html#v:-61--61- ):/=

$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
λ> :i Eq
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
        -- Defined in `GHC.Classes'

これはおそらくマイクロ最適化と見なされますが、場合によっては正当化される可能性があります。

于 2016-06-14T23:11:00.430 に答える
17

2 つのオブジェクトが等しいことについて質問することは意味があるが、それらが等しくないことについて質問することは意味がないという状況はあり得るでしょうか? (ユーザーの観点から、または実装者の観点から)

それは意見です。たぶんそうではありません。しかし、言語の設計者は全知ではなく、(少なくとも彼らにとっては) 理にかなっている状況を思いつく可能性のある人々を制限しないことに決めました。

于 2016-06-13T22:30:22.967 に答える
13

編集に応じて;

つまり、あるタイプが演算子を持ち、 を持た==ない!=、またはその逆が可能な場合、およびいつそうするのが理にかなっていますか。

一般的には、いいえ、意味がありません。通常、等値演算子と関係演算子はセットで提供されます。平等があれば不平等もある。<=同様のアプローチが算術演算子にも適用され、通常は自然な論理セットにも含まれます。

std::rel_opsこれは名前空間で証明されています。等号演算子と未満演算子を実装する場合、その名前空間を使用すると、元の実装された演算子に関して実装された他のものが得られます。

はいえ、一方が他方をすぐに意味しない、または他の観点から実装できない条件または状況はありますか? はい、間違いなく少数ですが、存在します。rel_ops繰り返しますが、独自の名前空間であることが証明されています。そのため、それらを個別に実装できるようにすることで、言語を活用して、コードのユーザーまたはクライアントにとって自然で直感的な方法で、必要なまたは必要なセマンティクスを取得できます。

前述の遅延評価は、この優れた例です。別の良い例は、平等や不平等をまったく意味しないセマンティクスを与えることです。これと同様の例は、ストリームの挿入と抽出に使用される<<ビットシフト演算子です。>>一般的なサークルでは眉をひそめられるかもしれませんが、一部のドメイン固有の領域では理にかなっている場合があります。

于 2016-06-14T18:29:52.757 に答える
12

==and!=演算子が実際には等価性を暗示していない場合、<<and>>ストリーム演算子がビットシフトを暗示していないのと同じように。記号を別の概念を意味するものとして扱う場合、相互に排他的である必要はありません。

同等性に関しては、ユースケースがオブジェクトを比較不可能なものとして扱うことを保証する場合、すべての比較が false (または、演算子が非 bool を返す場合は比較不可能な結果型) を返す必要がある場合、それは理にかなっています。これが正当化される特定の状況は考えられませんが、十分に合理的であることがわかりました。

于 2016-06-13T22:39:16.533 に答える
7

優れたパワーには、優れた責任が伴います。または、少なくとも本当に優れたスタイル ガイドが必要です。

==!=オーバーロードして、やりたいことを何でもすることができます。それは祝福でもあり、呪いでもあります。という保証はありませ!=!(a==b)

于 2016-06-18T16:12:27.647 に答える
5

最後に、これらの演算子で確認しているのは、式a == bora != bがブール値 ( trueor false) を返していることです。これらの式は、相互に排他的ではなく、比較後にブール値を返します。

于 2016-06-15T04:58:09.810 に答える
4

[..] なぜ 2 つの別個の定義が必要なのですか?

考慮すべきことの 1 つは、これらの演算子の 1 つを他の演算子の否定を使用するよりも効率的に実装できる可能性があるということです。

(ここでの私の例はくだらないものでしたが、要点は変わりません。たとえば、ブルーム フィルターを考えてみてください。セットに含まれていないものがあるかどうかをすばやくテストできますが、セットに含まれているかどうかをテストするには、さらに多くの時間がかかる場合があります。)

[..]定義上、a != bです!(a == b)

そして、それを保持するのはプログラマーとしてのあなたの責任です。おそらく、テストを書くのは良いことです。

于 2016-06-13T22:31:40.400 に答える
2

オペレーターの動作をカスタマイズすることで、希望どおりに動作させることができます。

あなたは物事をカスタマイズしたいかもしれません。たとえば、クラスをカスタマイズしたい場合があります。このクラスのオブジェクトは、特定のプロパティをチェックするだけで比較できます。これが事実であることを知っていれば、オブジェクト全体のすべてのプロパティのすべてのビットをチェックするのではなく、最小限のものだけをチェックする特定のコードを書くことができます。

何かが同じであることがわかるよりも速くはないにしても、同じくらい速く何かが違うことを理解できる場合を想像してみてください。確かに、何かが同じか違うかがわかれば、少しひっくり返すだけで反対のことがわかります。ただし、そのビットの反転は余分な操作です。場合によっては、コードが何度も再実行されると、1 つの操作を保存する (何倍にもする) ことで全体的な速度が向上することがあります。(たとえば、メガピクセル画面のピクセルごとに 1 つの操作を保存する場合、100 万回の操作を保存したことになります。これを 1 秒あたり 60 画面で乗算すると、さらに多くの操作を保存できます。)

hvd's answerは、いくつかの追加の例を提供します。

于 2016-06-18T00:20:42.850 に答える
2

はい、一方は「同等」を意味し、もう一方は「非同等」を意味し、この用語は相互に排他的であるためです。この演算子の他の意味は紛らわしいので、絶対に避けるべきです。

于 2016-06-29T23:01:48.627 に答える