Определение <для алгоритма сортировки STL - перегрузка оператора, функтор или автономная функция?

У меня есть stl:: list, содержащий объекты класса Widget. Они должны быть отсортированы в соответствии с двумя членами класса Widget.

Для сортировки для работы необходимо определить меньше, чем компаратор, сравнивающий два объекта Widget. Кажется, существует множество способов сделать это. Из того, что я могу собрать, можно либо:

а. Определите перегрузку оператора сравнения в классе:

bool Widget::operator< (const Widget &rhs) const

б. Определите автономную функцию, используя два виджета:

bool operator<(const Widget& lhs, const Widget& rhs);

И затем сделайте класс Widget своим другом:

class Widget {
    // Various class definitions ...
    friend bool operator<(const Widget& lhs, const Widget& rhs);
};

с. Определите функтор, а затем включите его в качестве параметра при вызове функции сортировки:

class Widget_Less :
public binary_function<Widget, Widget, bool> { 
    bool operator()(const Widget &lhs, const Widget& rhs) const;
};

Кто-нибудь знает, какой метод лучше? В частности, мне интересно узнать, должен ли я делать 1 или 2. Я обыскал книгу "Эффективный STL" Скотта Мейера, но, к сожалению, об этом нечего сказать.

Спасибо за ваш ответ.

Ответ 1

Если вы только сравниваете два виджета друг с другом, используйте элемент operator <. Если вы сравниваете Widget с чем-то другим, определите глобальный operator < (две версии параметров, необязательно друг класса Widget, но это отдельная проблема.

Функтор, которого вы действительно хотите, только если вы делаете что-то немного менее ортодоксальное. Выберите функтор, если сравнение "меньше" не имеет смысла в контексте виджетов. В этом случае наличие operator < может ввести в заблуждение. Конечно, функторы все же должны обеспечить заказ, но только потому, что это заказ, на самом деле не означает, что это операция "меньше". (Например, сортировка состояний по населению, вероятно, лучше для функтора, чем operator <.

Ответ 2

а. б. Оператор сравнения для двух виджетов не является интуитивным, как для меня. Теперь я не вижу, что он может сделать. Также, если эта функция не интуитивно понятна, когда вам понадобится один новый оператор сравнения, что вы можете сделать в этом случае?

Я предпочитаю функтор.

Ответ 3

Все они должны быть одинаковыми с точки зрения производительности, но между ними существуют другие различия:

  • Первые два, за исключением того, что вам нужно явно указать компаратор, и их можно легко использовать с другими операциями, возможно, с плохо определенными, которые не допускают явной спецификации компаратора.

  • Только функтор позволяет получить дополнительные данные для сравнения. Например, если бы вы сравнивали int s, вы могли бы создать сравнение, сравнивающее их расстояние от третьей точки P, которая была бы членом экземпляра functor.

  • Функторы, как правило, менее легко читать (тем, кто не знаком с С++).

Обратите внимание: вам не нужно наследовать binary_operator, чтобы он работал, хотя он дает вам несколько приятных typedef s.

Ответ 4

Для большинства целей a. и b. одинаковы. Итак, реальный вопрос: когда использовать a/b и когда использовать c.

Ответ: используйте a или b, если "меньше" имеет смысл для вашего объекта в недвусмысленных выражениях. Если ваш класс является числом, используйте <.

Если "меньше" не имеет смысла в контексте вашего класса, то, пожалуйста, не перегружайте "operator <" для вашего класса. Это смущает пользователей. Используйте c. вместо этого, и либо сделать его вложенным классом, либо typedef внутри вашего класса, чтобы вы могли записать его как Widget::Compare.