В моей работе у меня много петель с множеством внутренних вызовов функций; производительность критична здесь, и накладные расходы виртуальной функции вызывают неприемлемо, поэтому я стараюсь избегать динамического полиморфизма с помощью CRTP, например, так:Дизайн и стратегии полиморфизма во времени с использованием 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() } ...
но здесь работник имеет только объем в отрасли, если, и я бы это нужно, чтобы иметь жизнь длину программа. Кроме того, соответствующие параметры пользователя, вероятно, будут определять 4+ «политики», каждый из которых имеет несколько параметров (скажем, 4), поэтому кажется, что у вас быстрая неприятная проблема, когда шаблонный класс может принимать 1 из 4 * 4 * 4 * 4 комбинаций шаблонов.
Кроме того, перемещение логики цикла в типы не является вариантом - если бы это была служебная нагрузка для виртуальной функции, она была бы незначительной, и я бы использовал обычный полиморфизм. Фактический контроль циклов может быть довольно сложным и будет меняться во время выполнения.
Было ли это предположено, что я должен попытаться создать пользовательский итератор и передать это как аргумент функции и использовать обычный полиморфизм, или это приведет к подобным накладным расходам?
Что такое хороший дизайн для выбора классов во время выполнения, не прибегая к указателям на абстрактные базовые классы?
* «Теперь мне нужен фактический тип, чтобы он зависел от пользовательской опции времени выполнения». CRTP - это не способ создать динамическую диспетчеризацию. Я думаю, вы скорее ищете технику девиртуализации. – dyp
Вы можете связать решения пользователя с таблицей указателей функций ('std :: function') вместо использования 'switch'.Для другого варианта, если вам требуется более продолжительное время работы Рабочего, - это то, на что рассчитан динамический срок хранения (т. Е. Создание Рабочего в куче). – dyp
Что касается std :: function, [этот ответ] (http://stackoverflow.com/questions/10757167/do-function-pointers-force-an-instruction-pipeline-to-clear) утверждает, что такая вещь предотвратила бы любые поэтому это не является жизнеспособным вариантом. – Aurelius