I was wondering about the main differences, pros and cons in writing a higher order function taking, as input parameter, a std::function
or a forwarding reference, e.g. template<typename F> void hof(F&& fun);
.
Obviously, the former is more strict than the latter in that it specifies the function type that the input callable object has to conform to.
std::function
often has a significant run-time overhead. Passing a generic callable object through a template
parameter avoids std::function
's indirection costs and allows the compiler to aggressively optimize.
I wrote some simple benchmarks for lambda recursion (Y-combinator vs std::function
) at the end of this article. std::function
always generates at least 3.5x times more assembly than a non-polymorphic Y-combinator implementation. This is a decent example that shows how std::function
can be more expensive than a template
parameter.
I suggest playing around on gcc.godbolt.org to see assembly differences between the two techniques.
Here's an example I just came up with:
#if defined(STDFN)
void pass_by_stdfn(std::function<void()> f)
{
f();
}
#else
template <typename TF>
void pass_by_template(TF&& f)
{
f();
}
#endif
volatile int state = 0;
int main()
{
#if defined(STDFN)
pass_by_stdfn([i = 10]{ state = i; });
#else
pass_by_template([i = 10]{ state = i; });
#endif
}
With STDFN
not defined, the generated assembly is:
main:
mov DWORD PTR state[rip], 10
xor eax, eax
ret
state:
.zero 4
With STDFN
defined, the generated assembly is 48 lines long.
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