When I read litb answer to this question, I learned that passing an array by reference allows us to obtain its size. I just played little bit with code, and tried to pass a "function" by reference and surprisingly (at least for me), this code compiles:
void execute( void (&func)() ) // func is passed by reference!
{
func();
}
Is there any difference between the last function, and this one:
void execute( void (*func)() ) // func is passed by pointer!
{
func();
}
I tried it using VC2008, and it produces different output in each case. The strange thing is that the compiler optimizes the code better in case of a function pointer:
void print()
{
std::cout << "Hello References!";
}
void execute( void (&func)() ) // optimized
{
func();
}
int main()
{
00291020 call print (291000h)
}
=========================================
// In this case, the compiler removes all function calls in the code!
void print() // optimized!
{
std::cout << "Hello Pointers!";
}
void execute( void (*func)() ) // optimized
{
func();
}
int main()
{
002F1005 push offset string "Hello References!" (2F2124h)
002F100A push eax
002F100B call std::operator<<<std::char_traits<char> > (2F1150h)
}
There has to be a difference, although I don't see it, right?
Note: the code was compiled using VC2008, with /O2
and /Ot
turned on.
EDIT:: I am really interested about any difference between function references and function pointers. I examined the produced assembly code just to see how it is translated in each case.
For the language difference (keeping only the function declarations below, since that's what's important only)
void execute( void (&func)() );
void g();
int main() {
void (*fp)() = g;
execute(fp); // doesn't work
execute(&g); // doesn't work either
execute(g); // works
}
It doesn't work, because it wants a function, not a function pointer. For the same reason that array answer rejects a pointer, this rejects a pointer too. You have to pass "g" directly.
For templates, it matters too
template<typename T>
void execute(T &t) { T u = t; u(); }
template<typename T>
void execute(T t) { T u = t; u(); }
Those two are very different from one another. If you call it with execute(g);
like above, then the first will try to declare a function and initialize it with t
(reference to g
). The generated function would look like this
void execute(void(&t)()) { void u() = t; u(); }
Now you can initialize references and pointers to functions, but of course not functions itself. In the second definition, T
will be deduced to a function pointer type by template argument deduction, and passing a function will convert it to that pointer parameter type implicitly. So everything will go fine.
I don't know why MSVC treats them differently for inlining - but i also suspect it's because function references appear more seldom.
It's not as common an idiom, so it might just be that the VS team didn't add a rule to optimise it.
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