Функциональные объекты имеют довольно большой вес, но могут использоваться там, где полезная нагрузка достаточно велика (> 10000 циклов) или должна быть полиморфной, как в обобщенном планировщике заданий.
Они должны содержать копию вашего вызываемого объекта и обрабатывать любые исключения, которые он может выдать.
Использование шаблона значительно приближает вас к металлу, так как полученный код часто становится встроенным.
template <typename Func>
void doStuff(Foo& foo, Func operation)
{
Foo* fooPtr = &foo;
do
{
operation(*fooPtr);
} while (fooPtr->next && (fooPtr = fooPtr->next.get()));
}
Компилятор сможет заглянуть внутрь вашей функции и устранить избыточность.
На Golbolt ваш внутренний цикл становится
.LBB0_6: # =>This Loop Header: Depth=1
lea edx, [rax + 7]
mov rsi, rcx
.LBB0_7: # Parent Loop BB0_6 Depth=1
add dword ptr [rsi], edx
mov rsi, qword ptr [rsi + 8]
test rsi, rsi
jne .LBB0_7
mov esi, eax
or esi, 1
add esi, 7
mov rdx, rcx
.LBB0_9: # Parent Loop BB0_6 Depth=1
add dword ptr [rdx], esi
mov rdx, qword ptr [rdx + 8]
test rdx, rdx
jne .LBB0_9
add rax, 2
cmp rax, 100000000
jne .LBB0_6
В качестве бонуса, если вы не использовали связанный список, цикл может полностью исчезнуть.