2013-12-20 2 views
2

В моей работе у меня много петель с множеством внутренних вызовов функций; производительность критична здесь, и накладные расходы виртуальной функции вызывают неприемлемо, поэтому я стараюсь избегать динамического полиморфизма с помощью 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 комбинаций шаблонов.

Кроме того, перемещение логики цикла в типы не является вариантом - если бы это была служебная нагрузка для виртуальной функции, она была бы незначительной, и я бы использовал обычный полиморфизм. Фактический контроль циклов может быть довольно сложным и будет меняться во время выполнения.

Было ли это предположено, что я должен попытаться создать пользовательский итератор и передать это как аргумент функции и использовать обычный полиморфизм, или это приведет к подобным накладным расходам?

Что такое хороший дизайн для выбора классов во время выполнения, не прибегая к указателям на абстрактные базовые классы?

+0

* «Теперь мне нужен фактический тип, чтобы он зависел от пользовательской опции времени выполнения». CRTP - это не способ создать динамическую диспетчеризацию. Я думаю, вы скорее ищете технику девиртуализации. – dyp

+0

Вы можете связать решения пользователя с таблицей указателей функций ('std :: function') вместо использования 'switch'.Для другого варианта, если вам требуется более продолжительное время работы Рабочего, - это то, на что рассчитан динамический срок хранения (т. Е. Создание Рабочего в куче). – dyp

+0

Что касается std :: function, [этот ответ] (http://stackoverflow.com/questions/10757167/do-function-pointers-force-an-instruction-pipeline-to-clear) утверждает, что такая вещь предотвратила бы любые поэтому это не является жизнеспособным вариантом. – Aurelius

ответ

0

У вас есть классическая проблема отправки времени выполнения во время компиляции: «Кроме того, соответствующие параметры пользователя, вероятно, будут определять дополнительные политики, каждый из которых имеет несколько параметров». Ваш код должен поддерживать множество комбинаций опций, которые вы не знаете во время компиляции.

Это означает, что вам нужно написать код для каждой возможной комбинации, а затем отправить выбор пользователя на одну из комбинаций. Это означает, что у вас должен быть какой-то уродливый и не очень эффективный фрагмент кода, в котором вы разбираете решения пользователя во время выполнения и отправляете их на предопределенные шаблоны.

Чтобы максимально эффективно работать, вы хотите сделать эту отправку на очень высоком уровне, как можно ближе к точкам входа. С другой стороны, ваш низкоуровневый код можно запланировать столько, сколько захотите.

Это означает, что отправка может иметь несколько шагов от кода без шаблонов, чтобы смешивать шаблоны и опции, чтобы полностью вибрировать.

Обычно это достигается с помощью тегов и политик, а не CRTP, но это зависит от ваших алгоритмов и параметров.

Смежные вопросы