You can answer questions such as this for yourself by compiling into assembly language (with optimization, of course) and checking the output. If I prepare your example for a complete, compiled program ...
extern int f(); extern int g(); int direct() { return f() + g(); } int indirect() { int F = f(); int G = g(); return F + G; }
and compile it ( g++ -S -O2 -fomit-frame-pointer -fno-exceptions test.cc ; the last two switches eliminate a bunch of distractions from the output), I get this (further distractions are removed):
__Z8indirectv: pushq %rbx call __Z1fv movl %eax, %ebx call __Z1gv addl %ebx, %eax popq %rbx ret __Z6directv: pushq %rbx call __Z1fv movl %eax, %ebx call __Z1gv addl %ebx, %eax popq %rbx ret
As you can see, the code generated for both functions is identical, so there is no answer to your question, there will be no difference in performance. Now consider complex numbers β the same code, but s/int/std::complex<double>/g all over and #include <complex> at the top; the same compilation keys -
__Z8indirectv: subq $72, %rsp call __Z1fv movsd %xmm0, (%rsp) movsd %xmm1, 8(%rsp) movq (%rsp), %rax movq %rax, 48(%rsp) movq 8(%rsp), %rax movq %rax, 56(%rsp) call __Z1gv movsd %xmm0, (%rsp) movsd %xmm1, 8(%rsp) movq (%rsp), %rax movq %rax, 32(%rsp) movq 8(%rsp), %rax movq %rax, 40(%rsp) movsd 48(%rsp), %xmm0 addsd 32(%rsp), %xmm0 movsd 56(%rsp), %xmm1 addsd 40(%rsp), %xmm1 addq $72, %rsp ret __Z6directv: subq $72, %rsp call __Z1gv movsd %xmm0, (%rsp) movsd %xmm1, 8(%rsp) movq (%rsp), %rax movq %rax, 32(%rsp) movq 8(%rsp), %rax movq %rax, 40(%rsp) call __Z1fv movsd %xmm0, (%rsp) movsd %xmm1, 8(%rsp) movq (%rsp), %rax movq %rax, 48(%rsp) movq 8(%rsp), %rax movq %rax, 56(%rsp) movsd 48(%rsp), %xmm0 addsd 32(%rsp), %xmm0 movsd 56(%rsp), %xmm1 addsd 40(%rsp), %xmm1 addq $72, %rsp ret
This is a lot more instructions, and the compiler does not do the ideal optimization task, it seems, but nevertheless the code generated for both functions is identical.