28

要素の変化するリストを含む必要があるオブジェクトを初期化するために使用されるプログラムの可変個引数関数を置き換える手段として、リスト クラスを作成しました。リスト クラスには、私がとても気に入っている使用構文があります。ただ、使っているところを見たことがないので、それだけで使わないほうがいいのではないか?リストクラスの基本的な実装は次のようになります...

#include <list>
#include <iostream>
template<typename T>
struct list
{
    std::list<T> items;
    list(const list&ref):items(ref.items){}
    list(){}
    list(T var){items.push_back(var);}
    list& operator,(list add_){
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
    list& operator=(list add_){
        items.clear();
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
    list& operator+=(list add_){
        items.insert(items.end(),add_.items.begin(), add_.items.end());
        return *this;
    }
};

これにより、コードでこれを使用できるようになります...

struct music{
//...
};
struct music_playlist{
    list<music> queue;
//...
};
int main (int argc, const char * argv[])
{
    music_playlist playlist;
    music song1;
    music song2;
    music song3;
    music song4;
    playlist.queue = song1,song2; // The queue now contains song1 and song2
    playlist.queue+= song1,song3,song4; //The queue now contains two song1s and song2-4
    playlist.queue = song2; //the queue now only contains song2
    return 0;
}

構文は、通常の stl コンテナーを公開した場合よりもはるかに優れており、可変個引数関数よりもさらに優れている (そしてタイプセーフである) と本当に思います。しかし、私はこの構文が使用されているのを見たことがないので、何よりもコードが他のプログラマーに簡単に理解される必要があるため、それを避けるべきかどうかについて興味がありますか?

編集:

この質問と併せて、実際の問題の解決策をより対象としたこの質問を投稿しました。

4

8 に答える 8

40

<<QList のように演算子をオーバーロードしないのはなぜですか? 次に、次のように使用します。

playlist.queue << song1 << song2; // The queue now contains song1 and song2
playlist.queue << song1 << song3 << song4; //The queue now contains two song1s and song2-4
于 2011-07-18T05:19:25.390 に答える
20

あなたが書いたように、あなたの構文が見栄えがすることに同意します。
コードに関する私の主な問題は、次のものが同じであると予想されることです

playlist.queue = song1,song2;
playlist.queue = (song1,song2);  //more of c-style, as @Iuser notes.

しかし、実際にはそれらは完全に異なります。

これは危険です。なぜなら、コードに使い方のバグが入り込みやすいからです。括弧を使用してグループ化をさらに強調するのが好きな場合 (珍しいことではありません)、コンマが本当に面倒になる可能性があります。例えば、

//lets combine differnt playlists
new_playlist.queue =    song1        //the first playlist
                      ,(song3,song4) //the second playlist //opps, I didn't add song 3!
                      , song5;        //the third 

また

new_playlist.queue = (old_playlist.queue, song6); //opps, I edited my old playlist too!

ところで、boost.assign に出くわしたことがありますか: http://www.boost.org/doc/libs/1_47_0/libs/assign/doc/index.html

于 2011-07-18T06:22:00.797 に答える
11

最近優先順位が変わった?

playlist.queue = song1,song2;

これは次のように解析されます。

(playlist.queue = song1) , song2;

「,」と「+=」は同じです! コンマ演算子が一時的なリストを作成し、左右のアイテムを挿入して一時的なものを返す場合、より良いセマンティック マッチになります。次に、次のように記述できます。

playlist.queue = (song1,song2);

明示的な括弧付き。これは、C プログラマーがコードを読めるようになるための戦いのチャンスとなるでしょう。

于 2011-07-18T05:37:13.433 に答える
7

少し問題は、コンパイラがオーバーロードされた演算子コンマを選択できない場合、組み込み演算子の使用にフォールバックできることです。

対照的に、Boost.Assignで型を混同すると、コンパイル エラーが発生します。

#include <boost/assign.hpp>

int main()
{
    int one = 1;
    const char* two = "2";
    list<int> li;
    li = one, two;

    using namespace boost::assign;
    std::list<int> li2;
    li2 += one, two;
}
于 2011-07-18T06:50:57.550 に答える
5

これはおそらく Programmers に属するものですが、ここに私の 2 セントがあります。

かなり狭いコンテキストを持つコードについて話している場合、ユーザーがそれをいくつかの場所で使用し、それだけですべてである場合、,演算子のオーバーロードはおそらく問題ありません。特定のドメインで使用され、それ以外では使用されないドメイン固有言語を構築している場合は、おそらく問題ありません。

問題は、ユーザーがある程度の頻度で使用することを期待するもののために過負荷にしているときに発生します。

オーバーロード,とは、読者がコードの読み方を完全に再解釈する必要があることを意味します。彼らは式を見てすぐにそれが何をするのかを知ることはできません。あなたは、C++ プログラマーがコードのスキャンに関して行う最も基本的な仮定のいくつかをいじっています。

あなた自身の危険でそれをしてください。

于 2011-07-18T05:27:14.977 に答える
5

何よりもコードは他のプログラマーが簡単に理解できる必要があるため、それを避けるべきかどうかについて興味があります

他の C++ プログラマーがコードを簡単に理解できるようにすることが目標である場合、演算子をオーバーライドして標準 C++ の意味とは大きく異なる意味を与えることは、良い出発点ではありません。読者は、a) コンテナーの実装方法を理解し、b) コードを理解できるようにするためだけに、標準演算子の理解を再調整する必要はありません。

この種のブーストの前例を高く評価できます。あなたのコードを読むほとんどの人が Boost Assign にも精通していることが確実な場合は、演算子を独自にオーバーライドするのが妥当かもしれません。それでも、@badzeppelin の提案に従って、iostreams と同じように、代わりに operator<< を使用することをお勧めします。すべての C++ 開発者は、次のようなコードに出くわしたことがあると考えられます。

cout << "Hello world!"`

追加操作は、ストリームへの書き込みに非常に似ています。

于 2011-07-18T07:53:30.837 に答える
4

色んなレベルでヤバい…

あなたはオーバーライドlistしてシャドウイングしていますstd::list。大きなノーノー。独自のリスト クラスが必要な場合は、別の名前を付けてください。標準ライブラリをシャドウしないでください。

この,ような使い方は読めません。演算子の戻り値は右側のオペランドです。コードが機能したとしても、外部の読者にとってはその理由が明らかではなく、悪いことです。コードは読みやすいものであるべきですが、良いものではありません。

于 2011-07-18T05:13:12.197 に答える
2

具体的にコンマを使用することは悪いことではありませんoperator ,。悪用された場合、オペレーターは悪趣味を残します。あなたのコードには、合理的な問題は見られません。1つだけ提案したいのは、次のとおりです。

list& operator,(list &add_){  // <--- pass by reference to avoid copies
  *this += add_;  // <--- reuse operator +=
  return *this;
}

operator +=このように、ロジックを変更したい場合は、常に だけを編集する必要があります。私の答えは、読みやすさとコードのメンテナンス全般の観点からのものであることに注意してください。あなたが使用するビジネスロジックについては心配しません。

于 2011-07-18T05:13:45.453 に答える