In my work I have a lot of loops with many inner function calls; performance is critical here, and the overhead of virtual function calls is unacceptable, so I try to avoid dynamic polymorphism by using CRTP, like so:
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();
Aside: is the correct way to actually use a CRTP class? Now I need the actual type to depend on a runtime user option, and normally dynamic polymorphism with an abstract base class / strategy pattern would be the right design, but I can't afford the virtual function calls. One way to do this seems to be with some branching:
struct Worker {
void DoWork(){
if (option=="optionA"){
TypeA thing;
WorkLoop(thing); }
else if (option=="optionB"){
TypeB thing;
WorkLoop(thing); }
...
But this seems like a lousy design. Passing it as a template parameter here (or using policy based design) seems like an option:
template<class T>
struct Worker {
void DoWork(){ WorkLoop(&thing) };
T thing;
};
if (option=="optionA"){
Worker<TypeA> worker; worker.DoWork() } ...
but here worker only has scope in the if branch, and I'd need it to have a life the length of the program. Additionally, the relevant user options would probably specify 4+ "policies", each of those with several options (say 4), so it seems like you'd quickly have a nasty problem where a templated class could take 1 of 4*4*4*4 template combinations.
Also, moving the loop logic into the types is not an option - if it were the virtual function call overhead would be negligible and I'd use normal polymorphism. The actual control of the loops could be rather complicated and will vary at runtime.
Would this suggest that I should try and build a custom iterator and pass that as a function argument and use normal polymorphism, or would this incur similar overhead?
What is a good design for selecting classes at run-time without resorting to pointers to abstract base classes?