Oczywiście.
Wie, że wartość function
jest taka sama jak wartość, którą przekazuje, zna definicję funkcji, więc po prostu zamienia definicję bezpośrednio i wywołuje funkcję bezpośrednio.
Nie mogę wymyślić warunku, w którym kompilator nie zainicjuje jednoliniowego wywołania funkcji, po prostu zastępuje wywołanie funkcji wywołaniem funkcji, bez możliwej utraty.
Biorąc pod uwagę ten kod:
#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();
}
Z MANUALLY_INLINE
zdefiniowanym, otrzymujemy w ten sposób:
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
A bez tego:
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
samo. (Kompilacja z MSVC 2010, wydanie waniliowe.)
Brzmi dobrze w zasadzie, ale to zdać spróbować i zobaczyć test? Niestety nie jestem zbyt zajęty/obecnie, żeby to sprawdzić. Bardzo ciekawy, jak mi się to przydarzyło. – Potatoswatter
@Potatoswatter: Przeprowadzę teraz test, w jednej chwili. – GManNickG
@Potatoswatter: Zaktualizowano dla Twojej przyjemności oglądania. – GManNickG