在我的工作中,我有很多内部函数调用的循环;性能在这里很关键,虚函数调用的开销是不可接受的,所以我尝试通过使用 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模板组合。
此外,将循环逻辑移动到类型中也不是一种选择——如果是虚拟函数调用开销可以忽略不计,我会使用正常的多态性。循环的实际控制可能相当复杂,并且会在运行时发生变化。
这是否表明我应该尝试构建一个自定义迭代器并将其作为函数参数传递并使用正常的多态性,还是会产生类似的开销?
在运行时选择类而不求助于抽象基类的指针有什么好的设计?