Regarding Function passed as template argument, the community wiki answer provided by Ben Supnik discusses the issue of inlining instantiated function templates.
In that answer is the following code:
template<typename OP>
int do_op(int a, int b, OP op)
{
return op(a,b,);
}
int add(int a, b) { return a + b; }
int (* func_ptr)(int, int) = add;
int c = do_op(4,5,func_ptr);
The answer goes on to say this (in regards to the final line, which instantiates the function template do_op
):
clearly this is not getting inlined.
My question is this: Why is it clear that this is not getting inlined?
What he's saying (I think) is that the add
function is not getting inlined. In other words, the compiler might inline do_op
like this:
int c = func_ptr(4, 5);
but it won't also inline add
like this:
int c = 4 + 5;
However, he might be wrong in that simple example.
Generally, when you call a function through a pointer, the compiler can't know (at compile-time) what function you'll be calling, so it can't inline the function. Example:
void f1() { ... }
void f2() { ... }
void callThroughPointer() {
int i = arc4random_uniform(2);
void (*f)() = i ? f2 : f1;
f();
}
Here, the compiler cannot know whether callThroughPointer
will call f1
or f2
, so there is no way for it to inline either f1
or f2
in callThroughPointer
.
However, if the compiler can prove at compile-time what function will be called, it is allowed to inline the function. Example:
void f1() { ... }
void f2() { ... }
void callThroughPointer2() {
int i = arc4random_uniform(2);
void (*f)() = i ? f2 : f1;
f = f1;
f();
}
Here, the compiler can prove that f
will always be f1
, so it's allowed to inline f1
into callThroughPointer2
. (That doesn't mean it will inline f1
…)
Similarly, in the example you quoted in your post, the compiler can prove that func_ptr
is always add
in the call to do_op
, so it's allowed to inline add
. (That doesn't mean it will inline add
…)
When calling a function through a function pointer, the compiler is highly unlikely to avoid the call through the function pointer. Only if the compiler can prove that it knows what the function pointer is being initialized with and that it cannot be changed, it could possibly avoid the function call through the function pointer and, thus, inline the function. In the quoted setup, i.e.,
int (* func_ptr)(int, int) = add;
the function pointer func_ptr
is modifiable and the compiler is, thus, not guaranteed that it will never change. As a result, it cannot possibly inline the call to add
.
If the snippet of code is, indeed, complete, things happen during initialization and the compiler could actually, indeed, know that func_ptr
is initialized to contain add
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With