"Given sufficient optimization" the compiler might do it, depending on the characteristics of the functions f and g. If the compiler can see the definitions of the functions (so either they're in the same TU they're called from or you're using link time optimization), and can see that they have no side-effects and their results don't depend on any globals, then it can evaluate them only once instead of twice.
If they do have side effects, then you've demanded that they be called twice and so one of them will be evaluated twice.
If they're constexpr, it could call them no times.
For your example, using std::max(f(), g()) is generally more convenient than using intermediate variables. Like any function call it only evaluates each argument once.
Given this code:
int f(int x) {
return x + 1;
}
int g(int x) {
return x + 2;
}
int foo(int a, int b) {
return f(a) > g(b) ? f(a) : g(b);
}
gcc -O0 on my machine produces the following. Even if you can't read it, observe that callq <_Z1fi> occurs twice:
int foo(int a, int b) {
1e: 55 push %rbp
1f: 53 push %rbx
20: 48 83 ec 28 sub $0x28,%rsp
24: 48 8d ac 24 80 00 00 lea 0x80(%rsp),%rbp
2b: 00
2c: 89 4d c0 mov %ecx,-0x40(%rbp)
2f: 89 55 c8 mov %edx,-0x38(%rbp)
return f(a) > g(b) ? f(a) : g(b);
32: 8b 4d c0 mov -0x40(%rbp),%ecx
35: e8 c6 ff ff ff callq 0 <_Z1fi>
3a: 89 c3 mov %eax,%ebx
3c: 8b 45 c8 mov -0x38(%rbp),%eax
3f: 89 c1 mov %eax,%ecx
41: e8 c9 ff ff ff callq f <_Z1gi>
46: 39 c3 cmp %eax,%ebx
48: 7e 0a jle 54 <_Z3fooii+0x36>
4a: 8b 4d c0 mov -0x40(%rbp),%ecx
4d: e8 ae ff ff ff callq 0 <_Z1fi>
52: eb 0a jmp 5e <_Z3fooii+0x40>
54: 8b 45 c8 mov -0x38(%rbp),%eax
57: 89 c1 mov %eax,%ecx
59: e8 b1 ff ff ff callq f <_Z1gi>
}
5e: 48 83 c4 28 add $0x28,%rsp
62: 5b pop %rbx
63: 5d pop %rbp
64: c3 retq
whereas gcc -O2 produces:
int foo(int a, int b) {
return f(a) > g(b) ? f(a) : g(b);
20: 8d 42 02 lea 0x2(%rdx),%eax
23: 83 c1 01 add $0x1,%ecx
26: 39 c1 cmp %eax,%ecx
28: 0f 4d c1 cmovge %ecx,%eax
}
2b: c3 retq
Since it can see the definitions of f and g, the optimizer has had its way with them.
int a = std::max( f(), g() );pure(docu). Iffandgare specified this way the compile can optimize your code.