Производный Функтор с любым типом возврата и любыми параметрами - PullRequest
0 голосов
/ 05 мая 2009

У меня есть класс, который использует функторы в качестве единиц работы. Он принимает ссылку на функтор в своем методе Run (). Чтобы этот класс мог работать с любым функтором, все эти функторы должны быть производными от моего базового класса функторов, который выглядит следующим образом:

class baseFunctor{

public:
    virtual void operator()()=0;
    virtual baseFunctor Clone()=0;
};

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

Буду признателен за любые предложения о том, на какой путь смотреть.

Ответы [ 7 ]

2 голосов
/ 05 мая 2009

Как класс, вызывающий функтор, узнает, какие параметры предоставить и что делать с возвращаемым значением, если оно есть?

1 голос
/ 05 мая 2009

Я согласен с Нилом. Ваш основной класс должен знать, какие параметры передавать и какое возвращаемое значение ожидать от этих функторов. Можете ли вы просто привести тип «функтор» к соответствующему классу, который поддерживает функцию с необходимыми аргументами и возвращаемым значением?

class baseFunctor
{
};

class functor1x2: public baseFunctor
{
public:
    virtual void* execute(void*, void*);

}

class MainClass
{
public:
   void Execute(baseFunctor* ipFunctor)
   {
      functor1x2* lpFunctor1x2 = dynamic_cast<functor1x2*>(ipFunctor);
      if(lpFunctor1x2)
      {
         lpFunctor1x2->execute(NULL, NULL);
      }
   }
}

Я не уверен, что может быть достигнуто с помощью этого подхода, который не мог бы быть легче реализован с помощью шаблона Visitor, как заметил Дрю.

1 голос
/ 05 мая 2009

Итак, если я правильно читаю, у вас есть «Шаблон посетителя». Это может быть хорошо для вас, чтобы посмотреть вверх.

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

Если вам нужны универсальные функторы, которые принимают несколько аргументов в операторе (), шаблонирование приведет вас туда-сюда, но вам понадобится один аргумент на арность.

1 голос
/ 05 мая 2009

Если вы открыты для использования библиотеки Boost (www.boost.org), вас могут заинтересовать функции Boot.Bind и Boost.Function. Я использовал их в прошлом, чтобы достичь чего-то очень похожего на то, что вы обсуждаете.

Если вы используете Boost.Bind, вы можете выполнить каррирование на функторах, чтобы учесть различия между числом аргументов, которые ожидает функтор, и количеством аргументов, которые ожидает метод Run (то есть ноль). Код, который создает функтор, должен был бы связать любые аргументы с конкретными значениями и, таким образом, создать функтор с нулевым аргументом, который можно передать в Run ().

MV

0 голосов
/ 05 мая 2009

Возможно std :: tr1 :: function вам интересна?

0 голосов
/ 05 мая 2009

Я думаю, вам нужен аргумент с многоточием, например, varargs для C ++.

0 голосов
/ 05 мая 2009

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

Если вы планируете использовать наследование, ищите Covariant Return Types (и идиома Virtual Constructor ).

Теперь, суть проблемы: проблема на самом деле не в передаче функтора, а в применении функтора. Вы также можете взглянуть на boost::lambda и boost::parameter.

...