C++ can compilers inline a function pointer?
Sure thing.
It knows the value of function
is the same as the value it passes it, knows the definition of the function, so just replaces the definition inline and calls the function directly.
I can't think of a condition where a compiler won't inline a one-line function call, it's just replacing a function call with a function call, no possible loss.
Given this code:
#include <iostream>
template <typename Function>
void functionProxy(Function function)
{
function();
}
struct Functor
{
void operator()() const
{
std::cout << "functor!" << std::endl;
}
};
void function()
{
std::cout << "function!" << std::endl;
}
//#define MANUALLY_INLINE
#ifdef MANUALLY_INLINE
void test()
{
Functor()();
function();
[](){ std::cout << "lambda!" << std::endl; }();
}
#else
void test()
{
functionProxy(Functor());
functionProxy(function);
functionProxy([](){ std::cout << "lambda!" << std::endl; });
}
#endif
int main()
{
test();
}
With MANUALLY_INLINE
defined, we get this:
test:
00401000 mov eax,dword ptr [__imp_std::endl (402044h)]
00401005 mov ecx,dword ptr [__imp_std::cout (402058h)]
0040100B push eax
0040100C push offset string "functor!" (402114h)
00401011 push ecx
00401012 call std::operator<<<std::char_traits<char> > (401110h)
00401017 add esp,8
0040101A mov ecx,eax
0040101C call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40204Ch)]
00401022 mov edx,dword ptr [__imp_std::endl (402044h)]
00401028 mov eax,dword ptr [__imp_std::cout (402058h)]
0040102D push edx
0040102E push offset string "function!" (402120h)
00401033 push eax
00401034 call std::operator<<<std::char_traits<char> > (401110h)
00401039 add esp,8
0040103C mov ecx,eax
0040103E call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40204Ch)]
00401044 mov ecx,dword ptr [__imp_std::endl (402044h)]
0040104A mov edx,dword ptr [__imp_std::cout (402058h)]
00401050 push ecx
00401051 push offset string "lambda!" (40212Ch)
00401056 push edx
00401057 call std::operator<<<std::char_traits<char> > (401110h)
0040105C add esp,8
0040105F mov ecx,eax
00401061 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40204Ch)]
00401067 ret
And without, this:
test:
00401000 mov eax,dword ptr [__imp_std::endl (402044h)]
00401005 mov ecx,dword ptr [__imp_std::cout (402058h)]
0040100B push eax
0040100C push offset string "functor!" (402114h)
00401011 push ecx
00401012 call std::operator<<<std::char_traits<char> > (401110h)
00401017 add esp,8
0040101A mov ecx,eax
0040101C call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40204Ch)]
00401022 mov edx,dword ptr [__imp_std::endl (402044h)]
00401028 mov eax,dword ptr [__imp_std::cout (402058h)]
0040102D push edx
0040102E push offset string "function!" (402120h)
00401033 push eax
00401034 call std::operator<<<std::char_traits<char> > (401110h)
00401039 add esp,8
0040103C mov ecx,eax
0040103E call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40204Ch)]
00401044 mov ecx,dword ptr [__imp_std::endl (402044h)]
0040104A mov edx,dword ptr [__imp_std::cout (402058h)]
00401050 push ecx
00401051 push offset string "lambda!" (40212Ch)
00401056 push edx
00401057 call std::operator<<<std::char_traits<char> > (401110h)
0040105C add esp,8
0040105F mov ecx,eax
00401061 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40204Ch)]
00401067 ret
The same. (Compiled with MSVC 2010, vanilla Release.)
Comments
-
peoro about 2 years
Suppose I've got a function
functionProxy
that takes a generic parameterfunction
and call itsoperator()
:template< typename Function > void functionProxy( Function function ) { function(); }
The object passed to it may be:
a functor:
struct Functor { void operator()() const { std::cout << "functor!" << std::endl; } };
a function:
void function( ) { std::cout << "function!" << std::endl; }
a (C++0x) lambda function:
[](){ std::cout << "lambda!" << std::endl; }
int main( ) { functionProxy( Functor() ); functionProxy( function ); functionProxy( [](){ std::cout << "lambda!" << std::endl; } ); return 0; }
Will the compiler be able to inline
function
withinfunctionProxy
in all the above cases? -
Potatoswatter over 13 yearsSounds good in principle, but does it pass the try and see test? I'm unfortunately too busy right now/these days to check. Very curious though as this has occurred to me.
-
GManNickG over 13 years@Potatoswatter: Updated for your viewing pleasure.
-
peoro over 13 yearsUh, nice! Also GCC generates the same code (when optimizations are on).
-
Matthieu M. over 13 years@GMan: I suppose (unless LTO kicks in) that it is necessary for the function to be defined inline (and not in another translation unit) ?
-
GManNickG over 13 years@Matt: That sounds correct to me. I suppose I not only tested whether or not the call was inlined, but the functions as well. I'll test if you'd like, but I suspect that without the ability to inline the called function, it'll do the best it can and inline the call itself.
-
justin over 13 yearsalthough it actually adds to the instruction count, i've seen (specifically, older versions of) GCC pop one liners out of line when instruction counts are already high. if the (expanded) function body is already large, some simple calls may not be inlined.
-
Admin about 11 years@GManNickG Hey Nick, I saw this answer a while ago and I am running some problems with function pointers in MSVC 2012, I was wondering if you could help me! stackoverflow.com/questions/16462800/… Sorry if it's unpolite I ask it this way, but I didn't know how else to do it. I'd would add a bounty if that helps! Kind regards Christian