помогите кто чем может ) с оптимизацией кода.
Есть контейнер (не STL) при переборе элементов которого вызывается определённая сallback ф-я некоторого класса. На данный момент ф-я перебора выглядит так:
class CFoo
{
template <typename TCallee, HRESULT (TCallee::*pFunc)(CContainer*, CRecord*)>
HRESULT Iterate(TCallee* pCallee, /* ещё пара параметров */ )
{
подготовка, создание контейнера, заполнение и т.д.
итерация по элементам контейнера, вызов callback
for (...)
{
hRet = (pCallee->*pFunc)(pContainer, pContainer[i]);
}
очистка
}
}
есть ещё вариант, где callback ф-я имеет дополнительный параметр:
class CFoo
{
template <typename TCallee, typename TParam, HRESULT (TCallee::*pFunc)(CContainer*, CRecord*, TParam)>
HRESULT Iterate(TCallee* pCallee, TParam pParam /* ещё пара параметров */ )
{
здесь внутри всё то же самое, единственно что меняется это вызов callback
for (...)
{
hRet = (pCallee->*pFunc)(pContainer, pContainer[i], pParam);
}
}
}
Понятно, что ещё возможны варианты с callback'ами const типа:
и каждый раз единственное изменение это строка вызова, то есть 99% кода дублируется.
Рассмотрел вариант где подготовка и очистка выгружаются в отдельные ф-ии, там к сожалению есть свои проблемы, и такое решение в данном случае не является оптимизацией, скорее наоборот.
Есть другая идея, только с реализацией что-то никак. Сделать одну единтственную ф-ю, которая занимается перебором, и вызов callback'a как-то (как ?) настраивать в зависимости от обстоятельств.
Может быть есть и другие, лучшие или очевидные варианты решения проблемы.
Здравствуйте, smj, Вы писали:
smj>Здравствуйте,
smj>помогите кто чем может ) с оптимизацией кода. smj>Есть контейнер (не STL) при переборе элементов которого вызывается определённая сallback ф-я некоторого класса.
ну явно напрашивается решение с абстрагированием от конкретного callback'a... по сути итерационный алгоритм передеает туда 2 парамера -- контейнер (не пойму зачем) и запись из этого контейнера. простейший способ состоит в использовании функторов:
class CFoo
{
template <typename Func>
HRESULT Iterate(Func f, /* ещё пара параметров */ )
{
подготовка, создание контейнера, заполнение и т.д.
итерация по элементам контейнера, вызов callback
for (...)
{
hRet = f(pContainer, pContainer[i]);
}
очистка
}
}
функторы (в твоем случае имеющие 2 параметра) можешь создавать "на лету" делая binding необходимых тебе дополнительных параметров...
CFoo obj;
// call function w/o aux params
obj.Iterate(boost::bind(&another_obj::member_func, _1, _2));
// call function w/ one aux param
SomeParam p1;
obj.Iterate(boost::bind(&another_obj::member_func_with_param, _1, _2, p1));
// call function w/ two aux params
SomeParam p1;
SomeParam2 p2;
obj.Iterate(boost::bind(&another_obj::member_func_with_2_params, _1, _2, p1, p2));
альтернативный вариант состоит в написании итератора (совместимого с STLным) для твоего контейнера (используя для простоты например библиотечку boost::iterator)... в результате получишь возможность сувать свои итераторы в std:: алгоритмы...
PS: также луче избавиться от передачи контейнера в callback -- по хорошему все что должно быть нужно этой функции это элемент контейнера (ну или итератор на него)...
Здравствуйте, smj, Вы писали:
smj>Может быть есть и другие, лучшие или очевидные варианты решения проблемы.
А паттерн Шаблонный метод не подойдет?
В базовом абстрактном классе пишется вся функциональность за искллючением изменяющейся части, которая выделяется в абстрактный метод и вызывается в нужном месте.
Два наследника по-разному реализуют этот метод.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Здравствуйте, smj, Вы писали:
smj>>Может быть есть и другие, лучшие или очевидные варианты решения проблемы. LVV>А паттерн Шаблонный метод не подойдет? LVV>В базовом абстрактном классе пишется вся функциональность за искллючением изменяющейся части, которая выделяется в абстрактный метод и вызывается в нужном месте. LVV>Два наследника по-разному реализуют этот метод.
идея интересная, честно говоря, не совсем себе представляю как всё это дело увязать с шаблонами, надо будет поэкспериментировать. Видимо придётся всего наследника как класс параметризировать, и соответсвенно на каждый типа callback'а писать свой класс.
Здравствуйте, zaufi, Вы писали:
smj>>Есть контейнер (не STL) при переборе элементов которого вызывается определённая сallback ф-я некоторого класса. Z>ну явно напрашивается решение с абстрагированием от конкретного callback'a... по сути итерационный алгоритм передеает туда 2 парамера -- контейнер (не пойму зачем) и запись из этого контейнера. простейший способ состоит в использовании функторов:
Ага, это по идее то что надо.
Z>функторы (в твоем случае имеющие 2 параметра) можешь создавать "на лету" делая binding необходимых тебе дополнительных параметров... Z>obj.Iterate(boost::bind(&another_obj::member_func, _1, _2));
Буста к сожалению нет и не предвидется, поэтому вместо "на лету" придётся кустарным методом конфигурировать функтор, это не столь трагично.
Re[3]: Оптимизация кода
От:
Аноним
Дата:
08.04.09 11:34
Оценка:
Здравствуйте, smj, Вы писали:
smj>Здравствуйте, zaufi, Вы писали:
smj>>>Есть контейнер (не STL) при переборе элементов которого вызывается определённая сallback ф-я некоторого класса. Z>>ну явно напрашивается решение с абстрагированием от конкретного callback'a... по сути итерационный алгоритм передеает туда 2 парамера -- контейнер (не пойму зачем) и запись из этого контейнера. простейший способ состоит в использовании функторов:
smj>Ага, это по идее то что надо.
Z>>функторы (в твоем случае имеющие 2 параметра) можешь создавать "на лету" делая binding необходимых тебе дополнительных параметров... Z>>obj.Iterate(boost::bind(&another_obj::member_func, _1, _2));
smj>Буста к сожалению нет и не предвидется, поэтому вместо "на лету" придётся кустарным методом конфигурировать функтор, это не столь трагично.
functional есть в большинстве компиляторов в std::tr1::
Здравствуйте, smj, Вы писали:
smj>>>Может быть есть и другие, лучшие или очевидные варианты решения проблемы. LVV>>А паттерн Шаблонный метод не подойдет? LVV>>В базовом абстрактном классе пишется вся функциональность за искллючением изменяющейся части, которая выделяется в абстрактный метод и вызывается в нужном месте. LVV>>Два наследника по-разному реализуют этот метод.
smj>идея интересная, честно говоря, не совсем себе представляю как всё это дело увязать с шаблонами, надо будет поэкспериментировать. Видимо придётся всего наследника как класс параметризировать, и соответсвенно на каждый типа callback'а писать свой класс.
Шаблоны С++ здесь не обязательно использовать. Вот элементарный пример паттерна Шаблоннный метод:
-------------Базовый абстрактный класс
class Application
{ bool isDone;
protected:
virtual void Initialize() = 0;
virtual void Terminate() = 0;
virtual void Work() = 0;
virtual void setDone() { isDone = true; }
virtual bool Done() { return isDone; }
public:
Application(): isDone( false ) {}
void run() // шаблонный метод
{ Initialize(); // типовая инициализацияwhile( !Done() ) // условие завершения
{
Work(); // выполнение нужных действий
}
Terminate(); // завершение
}
};
------------------Наследник
class Program: public Application
{ int k;
protected:
virtual void Initialize() // инициализация
{ cout << "Initialize()" << endl; }
virtual void Terminate() // завершение
{ cout << "Terminate()" << endl; }
virtual void Work(); // основные действияpublic:
Program( int n ): k( n ) {}
};
void Program::Work() // основные действия
{ for( int i = 0; i < k; ++i ) cout << "Work() = " << k << endl;
setDone(); // завершение цикла в run
}
-----------Использование:
Application *pA = new Program( 111 );
pA -> run();
Program App( 10 );
App.run();
Можно в базовом классе оставить один абстрактный метод run(), который вызывается в общем коде.
А наследники реализуют его по разному. Тогда виртуальность сработает сама.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!