Подтвердить что ты не робот

Плюсы и минусы реализации функциональности как функтора

У меня есть дискуссия с коллегой об API простого класса, который имеет только один общедоступный метод. Я изначально пошел за:

class CalculateSomething
{
public:
  void operator()(const SomeObject &obj) const;

private:
  // ...
}

Однако мой коллега выступает против использования оператора() и хочет просто называть метод "вычислять" для ясности. Хотя я не считаю этот аргумент убедительным, это заставило меня задуматься о плюсах и минусах.

Преимущества operator()

  • Класс является худым и имеет одну четко определенную цель. После создания экземпляра он действует как свободная функция.
  • Это функтор и может быть легко использован как таковой (например, алгоритмы STL).
  • При использовании алгоритмов с диапазоном объект может передаваться напрямую, а не через указатель функции, который позволяет компилятору встраивать код. Хотя это и не гарантировано, передача его через указатель функции полностью запрещает эту возможность.

Недостатки operator()

  • Менее понятно, что делает этот метод, не глядя на имя класса. (Я лично не согласен с тем, что класс имеет только один метод, и поэтому его значение ясно из названия класса)
  • Ожидается, что большинство функторов в STL будут неактивными. Это, я думаю, является основной причиной, которая удерживает меня...

Я был удивлен, увидев, что мой поиск по этому поводу не вызвал многого, поскольку я бы предположил, что это довольно распространенный сценарий (один класс, одна ответственность). Таким образом, мне действительно интересно узнать, что думают другие люди.

4b9b3361

Ответ 1

Если lambdas действительно не вариант, ваш выбор должен зависеть от объема работы, которую этот объект берет на себя... и вызывать свои условные обозначения или стили кодирования. Вы можете решить быть явным (см. Werolik), это хорошо, если метод относительно незнакомы и требует состояний, но

Давайте рассмотрим простые примеры использования из стандартной библиотеки...

  • std:: hash: Это объект функции, который выполняет одно задание, и делает это якобы хорошо, не оспаривает этого
  • так много других... включая std:: less и его ассортимент

Одна вещь, которую вы видите вместе со всеми, заключается в том, что они глаголы... В моей перспективе, если ваш класс точно так же, как вы опубликовали фрагмент, CalculateSomething означает действие для меня, поэтому я всегда могу указать его как CalculateSomething()(my_object...).

И, как вы процитировали, он очень удобен в использовании самого алгоритма STL и многих других библиотек С++. Если вы примете метод коллеги, вам может потребоваться использовать std:: binds и lambdas, потому что вы хотите "адаптировать" интерфейс.

Пример:

class CalculateSomething
{
    public:
         void operator()(const SomeObject &obj) const;
    private:
         // ...
}

class CalculateNothing
{
    public:
         void calculate(const SomeObject &obj) const;
    private:
         // ...
}

Пример использования:

std::for_each(container.begin(), container.end(), CalculateSomething());

против

std::for_each(container.begin(), container.end(), [ c = CalculateNothing()](auto x) { c.calculate(x); });

Я думаю, что предпочитаю первое.

Ответ 2

Ну, вот и мои 5 центов.

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

В любом случае, предполагая, что класс требуется.

  • Мне не нравится использовать operator(). Возможно, с дополнительными комментариями.
  • Возможно, было бы хорошо переименовать его в 'SomethingCalculator' - разве это не объект?
  • Чем вы можете добавить метод, например 'DoWork', 'Calculate' или что-то еще.

Это сделает его более явным.

UPD. Все вышеизложенное может быть по-прежнему аргументировано, но я действительно верю, что добавление достаточной документации внутри кода сделает реальную разницу независимо от имени метода.