Как указывает phooji
, ваша реализация страдает от небольшой проблемы: она быстро генерирует длинный список вызовов, что заставит компиляторы быстро подавиться.
Вы можете обойти эту проблему, внедрив немного большесложная версия, использующая бинарную декомпозицию.Я также сделаю это универсальным для функтора, потому что я ленивый.
// Signature
template <Functor F, unsigned N>
struct UnrolledLoop;
Нам нужен вспомогательный шаблон, который сохраняет смещение параметра для передачи
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl;
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 0, OffSet>
{
static F run(F f) { return f; }
};
template <Functor F, unsigned OffSet>
struct UnrolledImpl<F, 1, OffSet>
{
static F run(F f) { f(OffSet); return f; }
};
template <Functor F, unsigned N, unsigned OffSet>
struct UnrolledImpl
{
static F run(F f) {
F f2 = UnrolledImpl<F, N/2, OffSet>::run(f);
return UnrolledImpl<F, N - N/2, OffSet + N/2>::run(f2);
}
};
ИВы можете реализовать UnrolledLoop
просто:
template <Functor F, unsigned N>
struct UnrolledLoop
{
static F run(F f) { return UnrolledImpl<F, N, 0>::run(f); }
}
Обратите внимание, что вы можете предоставить специализацию для большего количества значений N
(например, 3, 4) для компилятора.