简体   繁体   中英

How Best To Implement A Templated Class with Types That Depend On Each Other

As a simplified example, if I have the 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*/}
};

So the class ProcessEvent can take have two different sets of template types,

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

However, the second template type FooProcessor and BarProcessor are directly implied by the first template type and are implementation details the user doesn't care about. My goal is to have the same functionality as above, but have ProcessEvent take only a single template parameter, Foo or Bar. Other than through specialization of ProcessEvent, can this be done?

I'm going to assume that you simplified for clarity and are reallyusing smart pointers or at least properly managing the memory.

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.

You can do this 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, whenever you need BarProcessor and FooProcessor, respectively.

I would assume that a FooProcessor can only process Foo and a BarProcessor can only process Bar, but the other types could have more than one processor class. Thus you could do it intrusively:

class FooProcessor 
{
public:
   typedef Foo value_type;
};

class BarProcessor
{
public:
   typedef Bar value_type;
};

You could 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 could use an adapter class like Matt Phillips's but in reverse, so it takes the process class as template parameter:

template<typename T>
class Spec
{        
};

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

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

With intrusive typing and the Spec adapter typing your ProcessEvent template would take the processor type as parameter and derive the other one using value_type or type.

With polymorphism, your ProcessEvent would take the object type as parameter (Foo or Bar) and would be passed a processor that derives from Processor or Processor to process events.

If there are huge numbers of events to process and it is always processing them with the same object, the latter method would of course be slightly less efficient as it is processing through a v-table. It depends partly how long they take to process and whether the function that does it could be inlined.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM