В моей работе много циклов с множеством внутренних вызовов функций; здесь важна производительность, а накладные расходы на вызовы виртуальных функций неприемлемы, поэтому я стараюсь избегать динамического полиморфизма, используя 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), поэтому кажется, что у вас быстро возникнет неприятная проблема, когда шаблонный класс может принять 1 из 4 * 4 * 4*4 комбинации шаблонов.
Кроме того, перенос логики цикла в типы не вариант - если бы это было, накладные расходы на вызов виртуальной функции были бы незначительными, и я бы использовал обычный полиморфизм. Фактическое управление циклами может быть довольно сложным и будет меняться во время выполнения.
Может ли это означать, что я должен попытаться создать собственный итератор и передать его в качестве аргумента функции и использовать обычный полиморфизм, или это повлечет за собой аналогичные накладные расходы?
Как лучше выбрать классы во время выполнения, не прибегая к указателям на абстрактные базовые классы?
std::function
s) вместо использованияswitch
. Для другого варианта, если вам нужно более длительное время жизни Worker - для этого предназначена продолжительность динамического хранения (т.е. создайте Worker в куче). - person dyp   schedule 21.12.2013Func
. - person dyp   schedule 21.12.2013Func
внутри цикла, вам нужно выбрать конкретныйWorkLoop
, где вызываемыйFunc
известен во время компиляции. Этот выбор можно сделать с помощью переключателя/разветвления, таблицы функций, фабрики. - person dyp   schedule 21.12.2013