Reputation: 5255
I want to pass lambda function as callback to another function:
void test(const std::function<void()> fn){
fn();
}
It works, all ok. But. It does not inline it, no matter how high compiler optimization level I use:
proof
And when I play a while, I found, that with template -it becomes inlined:
template<typename T>
void test2(T fn){
fn();
}
So... Is there any way to make it inlined without templates? And why it becomes inlined with template declaration? Only function type is passing as template argument, not the function itself.
Upvotes: 13
Views: 4704
Reputation: 171127
Short answer: no, you can't make this work without templates (in the general case). The reason is that each lambda expression in your source code generates a unique type for that lambda closure. Proof:
auto f1 = [] { return 1; };
auto f2 = [] { return 1; };
static_assert(!std::is_same<decltype(f1), decltype(f2)>::value, "He's wrong");
Therefore, to accept an arbitrary closure, you either have to use a template, or a type-erasure wrapper (such as std::function
). Of course, type erasure relies on runtime polymorphism, so it doesn't lend itself to inlining.
The only way you could potentially make this work is with a stateless lambda (no capture), which has an implicit conversion to a pointer to function. Have your algorithm take the parameter as such a pointer to function, and hope the optimiser sees deep enough to inline the call. In other words, change the function to this:
void test(void (*fn)()) {
fn();
}
Upvotes: 12