What is the best way to implement a template class with types that depend on each other

As a simplified example, if I have classes

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*/} }; 

Thus, a ProcessEvent class can have two different sets of template types,

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

However, the second type of template FooProcessor and BarProcessor is directly implied by the first type of template and represent implementation details that the user does not need. My goal is to have the same functions as above, but ProcessEvent accepts only one template parameter - Foo or Bar. Can this be done differently than through the ProcessEvent specialization?

+4
source share
3 answers

You can do it as follows:

 template<typename T> class Spec { }; template<> class Spec<Foo> { typedef FooProcessor type; }; template<> class Spec<Bar> { typedef BarProcessor type; }; 

Then use Spec<T>::type , with T = Bar or T = Foo, when you need BarProcessor and FooProcessor respectively.

+4
source

I'm going to assume that you are simplified for clarity and are really using smart pointers, or at least manage memory correctly.

The easiest way to do this is with a typedef in the first class:

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

Then in your template, get rid of U and use typename T::Processor instead.

+6
source

I would suggest that FooProcessor can only process Foo, and BarProcessor can only process Bar, but other types can have more than one processor class. So you can do this obsessively:

 class FooProcessor { public: typedef Foo value_type; }; class BarProcessor { public: typedef Bar value_type; }; 

You can use polymorphism:

 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 }; 

You can use the adapter class, for example Matt Phillips, but in the reverse order, so the process class is required as a template parameter:

 template<typename T> class Spec { }; template<> class Spec<FooProcessor> { typedef Foo type; }; template<> class Spec<Bar> { typedef BarProcessor type; }; 

With an intrusive type and a Spec adapter, typing your ProcessEvent template will take the processor type as a parameter and select another one using value_type or type.

With polymorphism, your ProcessEvent will take the type of the object as a parameter (Foo or Bar) and a processor will be transferred that comes from the Processor or Processor for processing events.

If there are a huge number of events to process and it always processes them with the same object, the latter method, of course, will be somewhat less efficient, since it processes the v-table. Partly depends on how much time they spend processing, and whether the function that does this can be built-in.

+1
source

Source: https://habr.com/ru/post/1395437/


All Articles