1

studentsubclassでクラスを作成しましたcomparator。のコンストラクターは、生徒を比較する方法を指定するcomparatorという 1 つの引数を取ります。cmp_mode

class student
{
public:
    std::string name;
    int course, group;

    student(std::string name,
            int course,
            int group): name(name)
    {
        this->course = course;
        this->group = group;
    }

    enum cmp_mode
    {
        NAME,
        COURSE,
        GROUP
    };

    class comparator
    {
        cmp_mode mode;

    public:
        comparator(cmp_mode mode)
        {
            this->mode = mode;
        }

        bool compare(student s1, student s2)
        {
            if (mode == NAME)
                return s1.name < s2.name;
            else if (mode == COURSE)
                return s1.course < s2.course;
            else if (mode == GROUP)
                return s1.group < s2.group;
            else
                throw "Oh god! We can't compare variables using these keys!";
        }
    };

};

また、listofを作成したstudentsので、コンパレータ サブクラスを使用してこのリストを並べ替えたいと思います。

std::list<student> l;

student st1("Anya", 2, 5);
student st2("Misha", 4, 2);
student st3("Yasha", 1, 3);

l.push_back(st1);
l.push_back(st2);
l.push_back(st3); 

student::comparator by_group(student::GROUP);

l.sort(by_group.compare);

しかし、次のエラーが発生します。

ERROR: Reference to non-static member function must be called.

それで、私は何をすべきですか?より良い方法で並べ替えを調整するにはどうすればよいですか?

4

3 に答える 3

3

私はあなたのコメントから始めています:

ケースごとに比較関数を書けると思っていたのですが、さらに悪いようです。

なぜもっと悪いのですか?個人的には、実行が速く(少なくともコンパイルが速く)、保守が簡単(関数が短い)だと思います。

これは書くのがずっと簡単ではありませんか:

l.sort(student::compare_by_group);

そして、この実装は保守が簡単です:

class student
{
...    
    static bool compare_by_name(const student& s1, const student& s2)
    {
        return s1.name < s2.name;
    }
    static bool compare_by_course(const student& s1, const student& s2)
    {
        return s1.course < s2.course;
    }
    static bool compare_by_group(const student& s1, const student& s2)
    {
        return s1.group < s2.group;
    }

    // Add the followings only if you really need this stuff 
    // e.g. to get comparator type from elsewhere
    enum cmp_mode
    {
        NAME,
        COURSE,
        GROUP
    };

    static bool compare(cmp_mode, const student& s1, const student& s2)
    {
        switch(cmp_mode) {
          case NAME: return compare_by_name(s1, s2);
          ...
        }
    } 

};
于 2012-09-30T10:31:21.177 に答える
2

非静的メンバー関数には、関数がメンバーであるタイプの暗黙的なパラメーターがあります。動作するには、このタイプのインスタンスが必要です。オブジェクトを比較関数の最初のパラメーターに「バインド」するために使用できますstd::bind(またはboost.bindC ++ 11をサポートしていない場合) 。student::comparator

student::comparator by_group(student::GROUP);
using namespace std::placeholders;
auto comp = std::bind(student::comparator::compare, &by_group, _1, _2);
l.sort(comp);

上記のコードでは、by_groupオブジェクトは関数の最初の引数としてバインドされstudent::comparator::compare、結果の関数オブジェクトは2つのオブジェクトを受け取り、 :studentを返します。bool

std::cout << std::boolalpha;
const student& s1 = l[0];
const student& s2 = l[1];
std::cout << comp(s1, s2) << "\n"; // prints "true" or "false".

また、比較メンバー関数のシグネチャを次のように変更することをお勧めします

bool compare(const student& s1, const student& s2) const;

値を渡す理由はなく、メンバー関数が。でない理由もありませんconst

于 2012-09-30T07:10:08.847 に答える
2

Piotr のように、プロパティごとにコンパレータを作成することをお勧めします。これにより、高速でエラーが発生しにくくなります。ただし、静的関数の代わりにファンクター オブジェクトを使用することをお勧めします。

struct compare_by_name {
  bool operator()(const student& a, const student& b) const {
    return a.name < b.name;
  }
};

コンパレータが 1 回または 2 回だけ必要で、C++11 を使用している場合は、インライン ラムダを使用します。

l.sort([](const student& a, const student& b){ return a.name < b.name; });

動的コンパレータが絶対に必要な場合は、通常のファンクタ オブジェクトとして記述します。つまり、次のように定義しますoperator()

bool operator()(const student& a, const student& b) const {
  switch (mode) {
    case NAME:
      return a.name < b.name;
    // No default case, the constructor (if at all) should check whether the mode
    // is valid.
  }
}
于 2012-09-30T10:49:43.703 に答える