Может быть вопрос совершенно ламерский, но вот сижу-торможу и никак не сообразить...
Есть функция примерно следующего вида:
void f(double *pArray,int mode)
{
for (int k=0; k<K; k++)
{
Class *pObj=GetObj(k);
for (int i=From(k); i<To(k); i++)
{
if (!Condition(i))
continue;
switch (mode)
{
case 0:
pObj->Fun0(pArray[i]);
break;
case 1:
pObj->Fun1(pArray[i]);
break;
case 2:
pObj->Fun2(pArray[i]);
break;
case 3:
pObj->Fun3(pArray[i]);
break;
}
}
}
}
Т.е. в нее передается длинный массив, диапазоны индексов которого соответствуют некотором объектам.
Внутри каждого диапазона перебираются элементы массива и для тех из них, которые удовлетворяют некому условию, вызывается тот или иной метод соответствующего объекта.
Поскольку массив длинный, и функция вызывается часто, хочется, чтобы работала она по возможности быстрее. В этом смысле от ветвления внутри цикла хотелось бы избавиться. Но писать четыре совершенно идентичные за исключением имени методов Fun0-Fun3 функции неохота. Можно, конечно, вынести switch во внешний цикл, но это некая полумера — и код дублируется достаточно сильно, и если диапазонов много и они короткие — то прирост эффективности небольшой...
Подскажите, можно ли это эффективно сделать по-другому, без ненужного дублирования кода?
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, kfmn, Вы писали:
K>>Подскажите, можно ли это эффективно сделать по-другому, без ненужного дублирования кода?
J>Указатель на функцию поможет? J>Его можно передавать вместо mode, кстати, код станет чище.
Дык функции-то не статические! От разных объектов вызываются. Или я чего-то не понимаю?
Здравствуйте, kfmn, Вы писали:
K>Всем привет!
K>Может быть вопрос совершенно ламерский, но вот сижу-торможу и никак не сообразить... K>Есть функция примерно следующего вида:
K>
K>void f(double *pArray,int mode)
K>{
K> for (int k=0; k<K; k++)
K> {
K> Class *pObj=GetObj(k);
K> for (int i=From(k); i<To(k); i++)
K> {
K> if (!Condition(i))
K> continue;
K> switch (mode)
K> {
K> case 0:
pObj->>Fun0(pArray[i]);
K> break;
K> case 1:
pObj->>Fun1(pArray[i]);
K> break;
K> case 2:
pObj->>Fun2(pArray[i]);
K> break;
K> case 3:
pObj->>Fun3(pArray[i]);
K> break;
K> }
K> }
K> }
K>}
K>
K>Т.е. в нее передается длинный массив, диапазоны индексов которого соответствуют некотором объектам. K>Внутри каждого диапазона перебираются элементы массива и для тех из них, которые удовлетворяют некому условию, вызывается тот или иной метод соответствующего объекта.
K>Поскольку массив длинный, и функция вызывается часто, хочется, чтобы работала она по возможности быстрее. В этом смысле от ветвления внутри цикла хотелось бы избавиться. Но писать четыре совершенно идентичные за исключением имени методов Fun0-Fun3 функции неохота. Можно, конечно, вынести switch во внешний цикл, но это некая полумера — и код дублируется достаточно сильно, и если диапазонов много и они короткие — то прирост эффективности небольшой...
K>Подскажите, можно ли это эффективно сделать по-другому, без ненужного дублирования кода?
смотри "указатели на члены класса" .
//(осложнится синтаксис вызова, но будет ИМХО прозрачнее)void f(double *pArray , void (Class::*FunN)(double) )
{
for (int k=0; k<K; k++)
{
Class *pObj=GetObj(k);
for (int i=From(k); i<To(k); i++)
{
if (!Condition(i))
continue;
(pObj->*FunN)(pArray[i]);
}
}
}
f(A, & Class::Fun0 );
//Вариант, совместимый с твоей сигнатурой функции:void f(double *pArray , int mode )
{
void (Class::*FunN)(double);
switch(mode)
{
case 0: FunN = & Class::Fun0;
case 1: FunN = & Class::Fun1;
case 2: FunN = & Class::Fun2;
case 3: FunN = & Class::Fun3;
};
for (int k=0; k<K; k++)
{
Class *pObj=GetObj(k);
for (int i=From(k); i<To(k); i++)
{
if (!Condition(i))
continue;
(pObj->*FunN)(pArray[i]);
}
}
}
2) Шаблонная реализация функции:
(Будет своя реализация функции f для каждой вызываемой функции.)
template< void (Class::*FunN)(double) >
void f(double *pArray )
{
for (int k=0; k<K; k++)
{
Class *pObj=GetObj(k);
for (int i=From(k); i<To(k); i++)
{
if (!Condition(i))
continue;
(pObj->*FunN)(pArray[i]);
}
}
}
f<& Class::Fun0>(A);
Но ИМХО:
То чем ты сейчас занимаешся — экономия на спичках.
У тебя на каждой итерации вызов еще 3-х функций, + содержимое собственно FunN. Затраты на косвенный вызов функции и switch, наверняка очень малы по сравнению с прочими затратами.
Здравствуйте, kfmn, Вы писали:
K>Здравствуйте, jazzer, Вы писали:
J>>Здравствуйте, kfmn, Вы писали:
K>>>Подскажите, можно ли это эффективно сделать по-другому, без ненужного дублирования кода?
J>>Указатель на функцию поможет? J>>Его можно передавать вместо mode, кстати, код станет чище.
K>Дык функции-то не статические! От разных объектов вызываются. Или я чего-то не понимаю?
Указатель на функцию-член тоже можно передавать:
void f(double *pArray, void (Class::*Fun)(double))
{
for (int k=0; k<K; k++)
{
Class *pObj=GetObj(k);
for (int i=From(k); i<To(k); i++)
if (Condition(i))
(pObj->*Fun)(pArray[i]);
}
}
Здравствуйте, K13, Вы писали:
A>>От косвенности не избавишься, но код стал намного чище.
K13>Можно избавиться от косвенности за счет раздувания кода:
K13>
K13>template< int mode >
K13>void fImpl( double *pArray )
K13>{
K13> for (int k=0; k<K; k++)
K13> {
K13> Class *pObj=GetObj(k);
K13> for (int i=From(k); i<To(k); i++)
K13> {
K13> if (!Condition(i))
K13> continue;
K13> switch (mode)
K13> {
K13> case 0:
pObj->Fun0(pArray[i]);
K13> break;
K13> case 1:
pObj->Fun1(pArray[i]);
K13> break;
K13> case 2:
pObj->Fun2(pArray[i]);
K13> break;
K13> case 3:
pObj->Fun3(pArray[i]);
K13> break;
K13> default:
K13> assert( false );
K13> }
K13> }
K13> }
K13>}
K13>
K13>Компилятор должен выкинуть switch совсем, поскольку инстанцировав шаблон, обнаруживает что там константа.
Зачем же ждать от компилятора то, что несложно сделать самому:
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, rg45, Вы писали:
R>>Зачем же ждать от компилятора то, что несложно сделать самому:
AG>Я больше верю, что компилятор соптимизирует switch, чем соптимизирует такой вызов функции-члена до некосвенного вызова.
А, пардон, я как-то выпустил из виду, что в центре внимания лишняя косвенность. Тогда так:
class IClass
{
public:
virtual void Fun(double) = 0;
};
class CClass1 : public IClass
{
public:
// from basevirtual void Fun(double tmp){/*...*/};
};
void f(double *pArray,int mode)
{
for (int k=0; k<K; k++)
{
IClass* pObj=GetObj(k);
for (int i=From(k); i<To(k); i++)
{
if (!Condition(i))
continue;
pObj->Fun(pArray[i]);
}
}
}
Здравствуйте, kfmn, Вы писали:
K>Всем привет!
K>Может быть вопрос совершенно ламерский, но вот сижу-торможу и никак не сообразить... K>Есть функция примерно следующего вида: