Как лучше всего реализовать шаблонный класс с типами, которые зависят друг от друга - PullRequest
4 голосов
/ 08 февраля 2012

В качестве упрощенного примера, если у меня есть классы

template <class T, class U> class ProcessEvent
{
  public:
    ProcessEvent(T* t) : var1(t) { var2 = new U; }
    Process() { var2->Process(var1); }
  private:
    T* var1;
    U* var2;
};

class Foo 
{
  /*data*/
};

class FooProcessor 
{
  void Process(Foo* foo) {/*functionality*/}
};

class Bar
{
  /*data*/
};

class BarProcessor 
{
  void Process(Bar* bar) {/*functionality*/}
};

То есть класс ProcessEvent может иметь два разных набора типов шаблонов,

ProcessEvent<Foo, FooProcessor>
ProcessEvent<Bar, BarProcessor> 

Однако второй шаблонТип FooProcessor и BarProcessor непосредственно подразумеваются первым типом шаблона и являются деталями реализации, которые не интересуют пользователя.Моя цель - использовать те же функции, что и выше, но ProcessEvent должен принимать только один параметр шаблона, Foo или Bar.Может ли это быть сделано не через специализацию ProcessEvent?

Ответы [ 3 ]

6 голосов
/ 08 февраля 2012

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

Самый простой способ сделать это с помощью typedef в первом классе:

class Foo
{
    typedef FooProcessor Processor;
    // Stuff.
};

Затем в вашем шаблоне избавьтесь от U и используйте вместо него typename T::Processor.

4 голосов
/ 08 февраля 2012

Вы можете сделать это следующим образом:

template<typename T>
class Spec 
{
};

template<>
class Spec<Foo>
{
   typedef FooProcessor type;
};

template<>
class Spec<Bar>
{
   typedef BarProcessor type;
};

Затем используйте Spec<T>::type, с T = Bar или T = Foo, всякий раз, когда вам нужны BarProcessor и FooProcessor, соответственно.

1 голос
/ 08 февраля 2012

Я бы предположил, что FooProcessor может обрабатывать только Foo, а BarProcessor может обрабатывать только Bar, но другие типы могут иметь более одного класса процессоров. Таким образом, вы можете сделать это навязчиво:

class FooProcessor 
{
public:
   typedef Foo value_type;
};

class BarProcessor
{
public:
   typedef Bar value_type;
};

Вы можете использовать полиморфизм:

template< typename T >
class Processor
{
public:
   typedef T value_type;
   virtual ~Processor() {}
   virtual void process( value_type * ) = 0;
};

class FooProcessor : public Processor<Foo>
{
    // implement process
};

Вы можете использовать класс адаптера, как у Мэтта Филлипса, но в обратном порядке, поэтому он принимает класс процесса в качестве параметра шаблона:

template<typename T>
class Spec
{        
};

template<> class Spec<FooProcessor>
{           
     typedef Foo type;
};                

template<> class Spec<Bar>        
{           
    typedef BarProcessor type;        
};        

При навязчивой типизации и наборе адаптера Spec ваш шаблон ProcessEvent будет принимать тип процессора в качестве параметра и извлекать другой, используя value_type или type.

При полиморфизме ваше ProcessEvent будет принимать тип объекта в качестве параметра (Foo или Bar) и будет передаваться процессору, производному от Processor или Processor, для обработки событий.

Если существует огромное количество событий для обработки, и они всегда обрабатывают их одним и тем же объектом, последний метод, конечно, будет несколько менее эффективным, так как он обрабатывает через v-таблицу. Частично это зависит от того, сколько времени они занимают на обработку и может ли функция, которая это делает, быть встроенной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...