В моей программе мне нужно быстро перебирать циклический список, реализованный в виде массива. Медленная часть цикла - это операция остатка (деление!), Которая требуется для того, чтобы индекс не выпал из дальнего конца массива. Таким образом, я ловко разделил цикл на три части, чтобы избежать оставшейся операции.
Чтобы уменьшить дублирование кода, я создал макрос C и шаблон C ++ для циклической конструкции, показанной ниже:
template <typename F>
static inline void
for_loop_pairs(int at, int loops, const F fun) {
int right = MIN(loops, N - at - 1);
int left = loops - right;
while (right) {
int next = at + 1;
fun(at, next);
at = next;
next++;
right--;
}
if (left) {
fun(N - 1, 0);
left--;
at = 0;
while (left) {
int next = at + 1;
fun(at, next);
at = next;
next++;
left--;
}
}
}
#define FOR_LOOP_PAIRS(at, loops, fun) \
int right = MIN(loops, N - at - 1); \
int left = loops - right; \
int k0 = at; \
while (right) { \
int k1 = k0 + 1; \
fun; \
k0 = k1; \
k1++; \
right--; \
} \
if (left) { \
k0 = N - 1; \
int k1 = 0; \
fun; \
left--; \
k0 = 0; \
while (left) { \
k1 = k0 + 1; \
fun; \
k0 = k1; \
k1++; \
left--; \
} \
}
N
- это число элементов в массиве. Для вызова макроса и цикла for я использую:
FOR_LOOP_PAIRS(start, loops, {
// Do stuff with k0 and k1, which are the indices.
});
for_loop_pairs(start, loops, [&](int k0, int k1) {
// Do stuff with k0 and k1 which are the indices.
});
Версия с использованием шаблонов намного чище, но и на 5% медленнее, что недопустимо. Мой вопрос: что я делаю не так? Я ожидаю, что код шаблона выдаст точно такой же код, что и макрос.
Команда компиляции: g++ -Wall -Werror -fPIC -march=native -mtune=native -O3 -fomit-frame-pointer fname.cpp
gcc версия 7.4.0.