7

operator==C++ がクラスを自動的に定義できないことは理解していますが、使用できない場合!(a == b)に使用できないのはなぜですか?a != boperator!=operator==

std::rel_ops今日まで聞いたことがありませんでしたが、私は知っています。

4

4 に答える 4

7

operator==は必ずしも の反対を意味するわけではないからですoperator!=

operator==を意味しないインスタンスは考えられません!operator!=が、それらは別個の演算子です。C++ について最も解放的で、時には最も苛立たしいことの 1 つは、C++ がコードの記述方法に関して最小限の制限セットを適用することです。operator==の反対ではないインスタンスがある場合はoperator!=、C++ で表現できるはずです。実際、できます。

C++ では、良いことも悪いことも受け入れます。これは「悪い」のセットにあると考えることができます。

ほとんどの場合、 を正しく実装するのは簡単なことであることに注意してoperator!=くださいoperator==

bool Gizmo::operator!=(const Gizmo& rhs) const
{
  return !operator==(rhs);
}
于 2012-10-17T18:30:46.510 に答える
5

言語としての C++ は、ユーザーが明示的に要求しない機能を提供しません。この哲学がデフォルトのコンストラクターなどで少し壊れていることは知っていますが、これは Stroustrup が非常に早い段階で行った設計上の決定でし。そのため、コンパイラは、要求していないものを自動的に生成しません。

1993 年初頭に Bjarne からの電子メール チェーンへの参照がACCU Web サイトにあり、これについての言及が含まれています。私の記憶が正しければ、D&E にもあります。参考になるコピーが手元にありません。

于 2012-10-17T18:28:58.353 に答える
3

言語はあなたが望むことをすることを許されていません。operator==operator!=は2つの異なる演算子です。!(x==y)とが異なる結果をx!=yもたらす例を考えることはできませんが、operator<=vsを検討してoperator>ください。なぜこれらの両方が必要なのですか?x<=yと書くことができ!(x>y)ますよね?間違い。

#include<iostream>

int main () {
   double y = 0.0;
   double x = y/y;

   std::cout << " (x <= y) -> " << (x <= y) << "\n";
   std::cout << "!(x >  y) -> " << !(x > y) << "\n";
}
于 2012-10-17T19:14:47.680 に答える
1

C++ の最初のバージョン (修正後の別名 C++03) では、C++ で C をコンパイルできるようにするために、デフォルト コンストラクター、コピー コンストラクター、コピー代入演算子、およびデストラクターの自動定義が導入されました。

デストラクタのカスタム定義を提供する多くの人々は、コピー コンストラクタと代入演算子を定義するのを忘れてしまい、ひざの上で混乱することになります。

隠し実行パスなどの暗黙的なメソッドは、開発者を混乱させるようです。そして、私たちは皆噛まれたと思います。


ただし、C++11 には、オンデマンドのデフォルト メソッドのための非常に巧妙なメカニズムがあります。

class Test { Test() = default; }; // a rather useless class...

したがって、C++03 のコンストラクターの自動生成などの教訓を踏まえて、この自動生成の導入には賛成しませんが、次のことは確実にサポートします。

bool operator!=(Test const&, Test const&) = default;

operator==範囲内で、明らかに)

同様に:

bool operator>(Test const&, Test const&) = default;
bool operator<=(Test const&, Test const&) = default;
bool operator>=(Test const&, Test const&) = default;

operator<範囲内で、明らかに)


しかし、ここで本当の質問をするかもしれません: より一般的なメソッドを提供しないのはなぜですか?

operator==は一般的に失敗することはありませんが、私は の無数の壊れた実装を見てきましたoperator<。どうやら弱い順序を尊重することは、見かけほど簡単ではありません (*)。それでも、タプルについて考えてみると、それは 2 つのタプルを辞書的に比較したにすぎません。

(*) andの実装が一致しない (つまり、通常は<=> ) がありますが、タプルはそれを解決します!==<!(a < b) and !(b < a)a == b

実際:

std::tuple<int, std::string const&> to_tuple(Test const&);

一般に、初期演算子を生成するために使用できます。

template <typename T>
auto operator==(T const& left, T const& right) -> decltype(to_tuple(left), bool{}) {
    return to_tuple(left) == to_tuple(right);
}

template <typename T>
auto operator<(T const& left, T const& right) -> delctype(to_tuple(right), bool{}) {
    return to_tuple(left) < to_tuple(right);
}

それで、トラップは何ですか?さて、ADL。これらのテンプレートが、実装するクラスとは異なる名前空間に存在する場合、to_tupleADL によって自動的に取得されないため、物事がバラバラになります (同じ理由 whileusing std::swapは非常に一般的です...)。

したがって、スコープ内にあるbool operator==(Test const&, Test const&) = default;場合は正しいこと (tm) を実行する必要があると主張できます。to_tuple(Test const&)それはクレイジーでさえありません。多すぎない程度に。

しかし、私が元の提案からどれだけ離れているか見てください。委員会の決定が最終的にどうなるか想像してみてください...


そしてその間に?

まあ、個人的には、私は実装します:

#define MY_DEFINE_TUPLE_OPERATOR_IMPL(Type_, Op_)                       \
    inline bool operator Op_ (Type_ const& left, Type_ const& right) {  \
        return to_tuple(left) Op_ to_tuple(right);                      \
    }                                                                   \

#define MY_DEFINE_TUPLE_EQUAL(Type_)                                    \
    MY_DEFINE_TUPLE_OPERATOR_IMPL(Type_, ==)                            \
    MY_DEFINE_TUPLE_OPERATOR_IMPL(Type_, !=)

#define MY_DEFINE_TUPLE_COMP(Type_)                                     \
    MY_DEFINE_TUPLE_OPERATOR_IMPL(Type_,  <)                            \
    MY_DEFINE_TUPLE_OPERATOR_IMPL(Type_,  >)                            \
    MY_DEFINE_TUPLE_OPERATOR_IMPL(Type_, <=)                            \
    MY_DEFINE_TUPLE_OPERATOR_IMPL(Type_, >=)

その後:

class Test;

std::tuple<int, std::string const&> to_tuple(Test const&); // or boost::tuple

MY_DEFINE_TUPLE_EQUAL(Test);
MY_DEFINE_TUPLE_COMP(Test);

ADL で動作し、インライン コードを生成しto_tuple(それ自体がインラインである場合もそうでない場合もあります)、正確で一貫性のある実装を生成==し、6 つのメソッドすべて<よりもタイピングが少なくなります。= default

コンパイラ エラー メッセージのソースの場所も残します。

では...なぜ実際に言語をさらに複雑にするのでしょうか?

于 2012-10-17T19:40:32.740 に答える