C++ 基于CRTP的运行时多态性设计与策略

C++ 基于CRTP的运行时多态性设计与策略,c++,strategy-pattern,crtp,policy-based-design,C++,Strategy Pattern,Crtp,Policy Based Design,在我的工作中,我有很多内部函数调用的循环;性能在这里至关重要,虚拟函数调用的开销是不可接受的,因此我尝试通过使用CRTP来避免动态多态性,如下所示: template<class DType> struct BType { DType& impl(){ return *static_cast<DType*>(this); } void Func(){ impl().Func(); } }; struct MyType : public BType<

在我的工作中,我有很多内部函数调用的循环;性能在这里至关重要,虚拟函数调用的开销是不可接受的,因此我尝试通过使用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();
但这似乎是一个糟糕的设计。在此处将其作为模板参数传递(或使用基于策略的设计)似乎是一个选项:

template<class T>
struct Worker {
 void DoWork(){ WorkLoop(&thing) };
 T thing;
};
if (option=="optionA"){
 Worker<TypeA> worker; worker.DoWork() } ...
模板
结构工人{
void DoWork(){WorkLoop(&thing)};
T事物;
};
如果(选项==“选项A”){
Worker-Worker;Worker.DoWork()}。。。
但在这里,worker只在if分支中有作用域,我需要它有一个与程序长度相同的生命周期。此外,相关的用户选项可能会指定4+个“策略”,每个策略都有几个选项(比如4),因此似乎很快就会遇到一个棘手的问题,即一个模板化类可能需要4*4*4*4模板组合中的1个

此外,将循环逻辑移动到类型中不是一个选项——如果是这样,虚拟函数调用开销可以忽略不计,我会使用普通多态性。循环的实际控制可能相当复杂,并且在运行时会有所不同

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


在运行时选择类而不使用指向抽象基类的指针的好设计是什么?

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

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

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

这意味着dispatch可以有几个步骤,从非模板代码到模板和选项的混合,再到完全模板化


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

“现在我需要实际类型来依赖于运行时用户选项”CRTP无法创建某种动态调度。我认为您正在寻找一种设备化技术。您可以将用户决策链接到函数指针表(
std::function
s),而不是使用
开关。对于另一个选项,如果您需要更长的工作进程生命周期-这就是动态存储持续时间的目的(即在堆上创建工作进程)。关于std::function,声明这样做会阻止任何内联,因此这也不是一个可行的选项。我的意思是选择一个工作进程,不适用于
Func
函数。我不认为这样做可以避免为模板指定类型。
template<class T>
struct Worker {
 void DoWork(){ WorkLoop(&thing) };
 T thing;
};
if (option=="optionA"){
 Worker<TypeA> worker; worker.DoWork() } ...