Класс Functor выполняет работу в конструкторе

Я использую шаблоны С++ для передачи функторов стратегии, чтобы изменить поведение моей функции. Это работает нормально. Функтор, который я передаю, представляет собой класс без сохранения состояния и памяти, и он просто перегружает оператор () классическим способом функтора.

template <typename Operation> int foo(int a) 
{
int b=Operation()(a);
/* use b here, etc */
}

Я делаю это часто, и это работает хорошо, и часто я создаю шаблоны с 6 или 7 шаблонными функторами!

Однако я беспокоюсь как об элегантности кода, так и об эффективности. Функтор не имеет состояния, поэтому я предполагаю, что конструктор Operation() бесплатен, а вычисление функтора так же эффективно, как встроенная функция, но, как и у всех программистов на C++, у меня всегда есть некоторые мучительные сомнения.

Мой второй вопрос заключается в том, могу ли я использовать альтернативный функторный подход... тот, который не переопределяет оператор (), но делает все в конструкторе как побочный эффект! Что-то вроде:

struct Operation {
  Operation(int a, int &b) { b=a*a; }
};
template <typename Operation> int foo(int a) 
 {
   int b;
   Operation(a,b);
    /* use b here, etc */
 }

Я никогда не видел, чтобы кто-нибудь использовал конструктор как «работу» функтора, но, похоже, он должен работать. Есть ли преимущество? Какой-то недостаток? Мне нравится удаление странной двойной скобки "Operator()(a)" , но это, скорее всего, просто эстетика.


person SPWorley    schedule 07.03.2009    source источник


Ответы (5)


Какой-то недостаток?

  • Ctors не возвращают никаких полезных значений — их нельзя использовать в цепочках вызовов (например, foo(bar()).
  • Они могут бросить.
  • С точки зрения дизайна - ctors - это функции создания объектов, которые на самом деле не предназначены для того, чтобы быть рабочими лошадками.
person dirkgently    schedule 07.03.2009
comment
@Мыкола Голубев: Dtors -- по крайней мере, ты не должен бросать. - person dirkgently; 27.03.2009

  1. Компиляторы фактически встраивают пустой конструктор операции (по крайней мере, gcc в подобных ситуациях делает, за исключением случаев, когда вы отключили оптимизацию)
  2. Недостатком выполнения всего в конструкторе является то, что вы не можете таким образом создать функтор с некоторым внутренним состоянием - например. функтор для подсчета количества элементов, удовлетворяющих предикату. Кроме того, использование метода реального объекта в качестве функтора позволяет сохранить его экземпляр для последующего выполнения, чего нельзя сделать с помощью конструктора.
person jpalecek    schedule 07.03.2009

Судя по производительности, код, продемонстрированный с помощью, полностью оптимизирован как для VC, так и для GCC. Тем не менее, лучшая стратегия часто состоит в том, чтобы взять функтор в качестве параметра, так вы получите гораздо большую гибкость и идентичные характеристики производительности.

person Community    schedule 07.03.2009

Я бы рекомендовал определить функтор, который работает с STL-контейнерами, т.е. он должен реализовывать оператор(). (Всегда полезно следовать API языка, который вы используете.)

Это позволяет вашим алгоритмам быть очень общими (передавать функции, функторы, stl-bind, boost:: function, boost:: bind, boost:: lambda,...), что обычно и требуется.

Таким образом, вам не нужно указывать тип функтора в качестве параметра шаблона, просто создайте экземпляр и передайте его:

my_algorithm(foo, bar, MyOperation())
person Macke    schedule 07.03.2009

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

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

Класс должен быть автономным и инициализировать себя в хорошем состоянии. Похоже, вы играете с шаблонами, просто чтобы посмотреть, на что они способны.

person Martin York    schedule 08.03.2009