如何最好地实现具有相互依赖类型的模板类

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

本文关键字:类型 依赖 何最好 实现      更新时间:2023-10-16

作为一个简化的例子,如果我有类

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的专业化之外,还能做到这一点吗?

我假设您为了清晰起见进行了简化,并且实际使用了智能指针,或者至少正确地管理了内存。

最简单的方法是在第一类中使用typedef:

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

然后在模板中去掉U,改为使用typename T::Processor

您可以按如下方式执行此操作:

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

然后在需要BarProcessor和FooProcessor时分别使用Spec<T>::type,其中T=Bar或T=Foo。

我假设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
};

您可以使用类似Matt Phillips的适配器类,但反过来,它将流程类作为模板参数:

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表来处理的。这在一定程度上取决于它们需要多长时间来处理,以及执行处理的函数是否可以内联。