Consider this code (godbolt):
#include <iostream>
template<typename F> void call_by_val(F funct)
{
std::cout << "call_by_val(): ";
funct();
}
template<typename F> void call_by_ref(F& funct)
{
std::cout << "call_by_ref(): ";
funct();
}
template<typename F> void call_by_cref(const F& funct)
{
std::cout << "call_by_cref(): ";
funct();
}
void free_funct()
{
std::cout << "free_funct()\n";
}
int main()
{
call_by_val( free_funct );
call_by_ref( free_funct );
call_by_cref( free_funct );
}
All of these three calls work as expected. In case of a free function I'm not sure what's happening under the rug, so I'm wandering what's the difference in these three styles, semantically speaking. Is there an objective reason to prefer one over the others?
It is impossible to pass functions by-value. When a parameter of a function has a function type it is automatically adjusted to "pointer to [the function type]" instead. Similarly, deduction will decay the argument of function type to a function pointer before deduction if the function parameter is of non-reference type.
So, F
in the first call will be void(*)()
, not void()
.
In the reference overloads F
will be deduced to void()
.
const
has no meaning for references to functions and so the parameter in both the second and third call will be of type void(&)()
.
Whether funct
is a reference-to-function or pointer-to-function pretty much doesn't matter though, because you can call either as if you named the function directly. There is no difference in meaning except what decltype(funct)
would produce.