// Call the passed function object N times. This 'unrolls' the loop
// explicitly in assembly code, rather than creating a runtime loop.
template <unsigned int N, typename Fn>
void unroll(Fn&& fn) {
if constexpr (N != 0) {
unroll<N - 1>(fn);
fn(N - 1);
}
}
// extern function ensures the loop is not optimised away
extern void somethin(unsigned int i);
// Call somethin 4 times, passing the count each time
void four_somethins() {
unroll<4>([](unsigned int i) {
somethin(i);
});
}
Compiling on https://godbolt.org/ with flags -std=c++17 -O3
gives
four_somethins(): # @four_somethins()
push rax
xor edi, edi
call somethin(unsigned int)
mov edi, 1
call somethin(unsigned int)
mov edi, 2
call somethin(unsigned int)
mov edi, 3
pop rax
jmp somethin(unsigned int) # TAILCALL