2

在我的工作中,我有很多内部函数调用的循环;性能在这里很关键,虚函数调用的开销是不可接受的,所以我尝试通过使用 CRTP 来避免动态多态性,如下所示:

template<class DType>
struct BType {
  DType& impl(){ return *static_cast<DType*>(this); }
  void Func(){ impl().Func(); }
};

struct MyType : public BType<MyType> {
  void Func(){ /* do work */ }
};

template<class DType>
void WorkLoop(BType<DType>* func){
  for  (int i=0;i<ni;++i){ func->func(); }
}

struct Worker {
  void DoWork(){ WorkLoop(&thing) };
 private:
  MyType thing;
};

Worker worker;
worker.DoWork();

另外:实际使用 CRTP 类的正确方法是什么?现在我需要实际类型依赖于运行时用户选项,通常具有抽象基类/策略模式的动态多态性将是正确的设计,但我买不起虚函数调用。一种方法似乎是使用一些分支:

struct Worker {
  void DoWork(){
   if (option=="optionA"){
     TypeA thing;
     WorkLoop(thing); }
   else if (option=="optionB"){
     TypeB thing;
     WorkLoop(thing); } 
  ...

但这似乎是一个糟糕的设计。在此处将其作为模板参数传递(或使用基于策略的设计)似乎是一种选择:

template<class T>
struct Worker {
 void DoWork(){ WorkLoop(&thing) };
 T thing;
};
if (option=="optionA"){
 Worker<TypeA> worker; worker.DoWork() } ...

但是这里的 worker 只在 if 分支中有作用域,我需要它的生命周期与程序一样长。此外,相关的用户选项可能会指定 4+“策略”,每个选项都有几个选项(比如 4),所以看起来你很快就会遇到一个令人讨厌的问题,模板类可能会占用 4*4* 中的 1 个4*4模板组合。

此外,将循环逻辑移动到类型中也不是一种选择——如果是虚拟函数调用开销可以忽略不计,我会使用正常的多态性。循环的实际控制可能相当复杂,并且会在运行时发生变化。

这是否表明我应该尝试构建一个自定义迭代器并将其作为函数参数传递并使用正常的多态性,还是会产生类似的开销?

在运行时选择类而不求助于抽象基类的指针有什么好的设计?

4

1 回答 1

0

您有一个运行时到编译时分派的经典问题:“此外,相关的用户选项可能会指定额外的策略,每个策略都有几个选项”。您的代码必须支持许多您在编译时不知道的选项组合。

这意味着您必须为每个可能的组合编写一些代码,然后将用户的选择分配给其中一个组合。这意味着您必须有一些丑陋且效率不高的代码,您可以在其中解析用户的运行时决策并将它们分派到预定义的模板中。

为了保持尽可能高的效率,您希望在非常高的级别上执行此调度,尽可能靠近入口点。另一方面,您的低级代码可以随心所欲地模板化。

这意味着调度可以从非模板代码到混合模板和选项到完全模板化的几个步骤。

通常使用标签和策略而不是 CRTP 可以更好地实现它,但这取决于您的算法和选项。

于 2013-12-21T02:20:03.027 回答