繁体   English   中英

C ++可以编译内联函数指针吗?

[英]C++ can compilers inline a function pointer?

假设我有一个函数functionProxy ,它接受一个泛型参数function并调用它的operator()

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; } 
  • 一个(C ++ 0x)lambda函数:

     [](){ std::cout << "lambda!" << std::endl; } 

int main( )
{
    functionProxy( Functor() );
    functionProxy( function );
    functionProxy( [](){ std::cout << "lambda!" << std::endl; } );
    return 0;
}

在上述所有情况下,编译器是否能够在functionProxy中内联function

当然可以。

它知道function的值与它传递的值相同,知道函数的定义,所以只需替换内联定义并直接调用函数。

我想不出编译器不会内联单行函数调用的情况,它只是用函数调用替换函数调用,没有可能的损失。


鉴于此代码:

#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();
}

通过定义MANUALLY_INLINE ,我们得到:

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  

没有,这个:

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

相同。 (使用MSVC 2010编译,vanilla发布。)

尝试了以下模板化指针到lambda代码

volatile static int a = 0;

template <typename Lambda> class Widget {
   public: 
      Widget(const Lambda* const lambda) : lambda_(lambda) { }
      void f() { (*lambda_)(); }
   private:
      const Lambda* const lambda_;
};

int main() {
   auto lambda = [](){ a++; };
   Widget<decltype(lambda)> widget(&lambda);
   widget.f();
}

GNU g ++ 4.9.2,Intel icpc 16.0.1和clang ++ 3.5.0都使用-O2内联widget.f()(*lambda_)()调用。 也就是说, a根据反汇编的二进制文件直接在main()内增加。

即使使用非const lambdalambda_指针(删除两个const )也会应用内联。

同上一个局部变量和lambda捕获:

int main() {
   volatile int a = 0;
   auto lambda = [&a](){ a++; };
   ...

有可能。 没有强烈的理由支持或反对它,它只取决于编译器编写者实现的内容。

Functor和lambda将被内联,因为它们是无状态对象(所有信息在编译时都可用)。

函数指针和boost :: Function对象(现在在std::)中无法内联,因为它在编译时不清楚它们指向的是什么函数。 如果它们是常数,则可能会有所不同。

编译器是否能够内联调用? 是。

会吗? 也许。 在您知道它重要之后检查。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM