编译器决定调用函数`POW`,而不是在编译时对它进行评估。为什么?

时间:2016-04-11 12:59:37

标签: c++ runtime c++14 constexpr

我通过this comment@CaffeineAddict获得了下面的代码段。

#include <iostream>
template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
    return (expo != 0) ? base * POW(base, expo - 1) : 1;
}

int main(int argc, char** argv)
{
    std::cout << POW((unsigned __int64)2, 63) << std::endl;
    return 0;
}

从VS2015获得以下反汇编:

int main(int argc, char** argv)
{
009418A0  push        ebp  
009418A1  mov         ebp,esp  
009418A3  sub         esp,0C0h  
009418A9  push        ebx  
009418AA  push        esi  
009418AB  push        edi  
009418AC  lea         edi,[ebp-0C0h]  
009418B2  mov         ecx,30h  
009418B7  mov         eax,0CCCCCCCCh  
009418BC  rep stos    dword ptr es:[edi]  
    std::cout << POW((unsigned __int64)2, 63) << std::endl;
009418BE  mov         esi,esp  
009418C0  push        offset std::endl<char,std::char_traits<char> > (0941064h)  
009418C5  push        3Fh  
009418C7  push        0  
009418C9  push        2  
009418CB  call        POW<unsigned __int64,int> (09410FAh)     <<======== 
009418D0  add         esp,0Ch  
009418D3  mov         edi,esp  
009418D5  push        edx  
009418D6  push        eax  
009418D7  mov         ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (094A098h)]  
009418DD  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (094A0ACh)]  
009418E3  cmp         edi,esp  
009418E5  call        __RTC_CheckEsp (0941127h)  
009418EA  mov         ecx,eax  
009418EC  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (094A0B0h)]  
009418F2  cmp         esi,esp  
009418F4  call        __RTC_CheckEsp (0941127h)  
    return 0;
009418F9  xor         eax,eax  
}

显示(参见字符&#34;&lt;&lt; ======&#34;我在反汇编中介绍)编译器没有评估函数POW在编译时。从他的评论中,@CaffeineAddict似乎期望编译器出现这种行为。但我仍然无法理解为什么会出现这种情况呢?

1 个答案:

答案 0 :(得分:0)

有两个原因。

首先,不保证在编译时调用constexpr函数。要强制编译器在编译时调用它,必须先将它存储在constexpr变量中,即

constexpr auto pow = POW((unsigned __int64)2, 63);
std::cout << pow << std::endl;

其次,您必须在Release配置中构建项目。在VS中,如果使用Debug配置构建项目,您会发现可以通过constexpr函数进行断点。