10

Google C++ スタイル ガイドの演算子のオーバーロードに関するセクションでは、演算子をオーバーロードないことを推奨しています (「まれな特殊な状況を除く」)。具体的には、次のことを推奨しています。

特に、 クラスを STL コンテナーのキーとして使用できるようにするためだけにオーバーロードしoperator==ないでください。operator<代わりに、コンテナーを宣言するときに等値ファンクターと比較ファンクターの型を作成する必要があります。

そのようなファンクターがどのように見えるかについては少し曖昧ですが、私の主な質問は、なぜこれのために独自のファンクターを書きたいのですか? を定義operator<して標準std::less<T>関数を使用する方が簡単ではないでしょうか? 一方を他方よりも使用する利点はありますか?

4

7 に答える 7

16

より基本的な型を除いて、小なり演算は必ずしも自明ではなく、等しいかどうかでさえ状況によって異なる場合があります。

すべての乗客に搭乗番号を割り当てたい航空会社の状況を想像してみてください。この番号は(もちろん)搭乗順序を反映しています。では、誰が誰より先に来るかを決定するものは何ですか? 顧客が登録した順序だけを取得することもできます。その場合、小なり演算でチェックイン時間を比較します。また、顧客がチケットに支払った価格を考慮することもできます。チケットの価格を現在比較するよりも低くなります。

… 等々。全体として、並べ替えられたコンテナに乗客を入れる必要があるかもしれませんがoperator <、クラスでを定義することは意味がありません。PassengerそれがGoogleが警告していることだと思います。

于 2008-10-08T16:32:55.590 に答える
6

一般に、定義するoperator<方が適切で簡単です。

ファンクタを使用したい場合は、特定の型を比較す​​る複数の方法が必要な場合です。例えば:

class Person;

struct CompareByHeight {
    bool operator()(const Person &a, const Person &b);
};

struct CompareByWeight {
    bool operator()(const Person &a, const Person &b);
};

この場合、人々を比較して順序付けするための適切な「デフォルト」の方法がない可能性があるためoperator<、ファンクターを定義および使用しない方がよい場合があります。また、一般的に人は身長順に並べられるため、operator<を呼び出すだけでCompareByHeight、 Person を体重順に並べる必要がある人はCompareByWeight明示的に使用する必要があるとも言えます。

多くの場合、問題はファンクターの定義がクラスのユーザーに任されていることです。そのため、順序付けられたコンテナーでクラスを使用する必要があるときはいつでも、同じことを何度も再定義する傾向があります。

于 2008-10-08T16:54:00.150 に答える
5

あなたが引用した Web ページによると、ファンクターにはあまり利点がありません (「[演算子] は、高価な操作が安価な組み込み操作であると考えるように私たちの直感をだますことができます。」)

私の考えでは、クラスをできる限りファースト クラスのオブジェクトにするように努力する必要があります。

ファンクターを書いてからしばらく経ちましたが、次のようになります。

class MyClass {....}

class LessThanMyClass : std:binary_function<MyClass, MyClass, bool>
{
    public bool operator()(MyClass lhs, MyClass rhs) 
    {   return /* determine if lhs < rhs */ ; }
}

vector<MyClass> objs;
std::sort(objs.begin(), objs.end(), LessThanMyClass());

}

于 2008-10-08T16:29:05.990 に答える
3

operator< を定義しないことの背後にあるメッセージは、順序付けはオブジェクトではなくコレクションのプロパティであるということだと思います。同じオブジェクトのコレクションが異なれば、順序が異なる場合があります。そのため、operator< ではなく、コレクションの型を指定するときに使用する別のファンクターを使用する必要があります。

ただし実際には、多くのクラスに自然な順序付けがあり、それがアプリケーションのコレクションで使用される唯一の順序付けになります。それ以外の場合、順序付けはアプリケーションに関係なく、後でアイテムを見つけることができるようにコレクションにのみ関係する場合があります。このような場合、operator< を定義することは完全に理にかなっています。

オブジェクト モデルを設計するときは、現実世界のサブセットのみをモデル化していることを思い出してください。現実の世界では、同じクラスのオブジェクトをランク付けするさまざまな方法が無数にあるかもしれませんが、私たちが取り組んでいるアプリケーション ドメインでは、関連するものがあるかもしれません。

コードが進化して、最初の順序付けと同じくらい適切な 2 番目の順序付けが必要になった場合は、クラスをリファクタリングして operator< を削除し、両方のランキング関数を別々のファンクターに配置する必要があります。これは、どのランキングも他のランキングよりも重要ではないという意図を示しています。

算術演算子に関しては、算術型を実装する場合を除き、これらをオーバーロードしないでください。

もちろん、すべての規則には例外があります。例外を作成する必要があるかどうかがわからない場合は、おそらくすべきではありません。経験があなたのガイドになります。

于 2008-10-08T21:36:16.680 に答える
3

私はおそらく、Google スタイル ガイドまでは行かないでしょう。

彼らが得ているのは、 and をオーバーロードoperator<するとoperator==、型を使用するたびに決定を下しているのに対し、ファンクター型はそのコレクションにのみ適用されるということだと思います。

コンパレーターが必要なのはアイテムをコレクションに入れることだけである場合は、すべてのコンテキストに適用される演算子ではなく、そのコンテキスト専用の関数を用意することをお勧めします。

購入注文を時系列で並べ替えたい場合もありますが、一般的には合計金額で比較するのが理にかなっています。operator<日付を比較してコレクションにロードできるようにオーバーロードすると、別のクライアントがoperator<合計価格を比較すると考える可能性がある私たちの日付を誤用するリスクが生じます。

于 2008-10-08T17:06:17.113 に答える
2

ファンクターは、 を持つクラスoperator ()です。この場合、メソッドは比較対象の型の 2 つのパラメーターを取りbool、最初のパラメーターが 2 番目のパラメーターより小さい場合に結果を返します。

編集:ジェームズ・カランが言ったことに基づいて構築するには、クラス内でファンクターを定義できます。たとえば、次のようになります。

class MyClass
{
    struct LessThan : public std::binary_function<MyClass, MyClass, bool>
    {
        bool operator()(const MyClass & first, const MyClass & second) const
        {
            return first.key < second.key;
        }
    };
};
于 2008-10-08T16:29:50.573 に答える
1

皮肉なことに、ファンクタは演算子 (関数呼び出し演算子 - operator ()) もオーバーライドする必要があるため、その意味がわかりません。

于 2008-10-08T16:31:44.407 に答える