2016-04-11 66 views
0

我通過@CaffeineAddictthis comment得到了下面的代碼片段。編譯器決定調用函數「POW」,而不是在編譯時對其進行評估。爲什麼?

#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 [[email protected]@@[email protected][email protected]@[email protected]@@[email protected] (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 
} 

其示出了(見我在拆卸引入字符「< < ==」),編譯器沒」 t在編譯時評估函數POW。從他的評論看,@CaffeineAddict似乎期待編譯器的這種行爲。但我仍然無法理解爲什麼這是所期望的呢?

+1

你**期待的是什麼?您從來沒有要求編譯器在編譯時對其進行評估。 (你的頭銜似乎與這個問題的主體相矛盾......) –

+0

@MarcGlisse函數'POW'是'constexpr',它用常量表達式調用。我剛剛編輯了標題。感謝您的關注。 –

+0

查看調試構建代碼gen永遠不會非常有用。使用const auto value = POW (2,63);強制編譯器做你想做的事情,並保證獲得滿意的結果。通過傳遞(2,-1),而不是通過傳遞(2,-1)來了解爲什麼這會使保修失效:) –

回答

0

兩個原因。

首先,constexpr函數不保證在編譯時調用。要強制編譯器在編譯時調用它,你必須其次,它存儲在一個constexpr變量第一,即

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

,你必須建立在發佈配置項目。在VS中,如果使用Debug配置構建項目,則會發現可以通過constexpr函數進行分解。

+0

看起來像VS2015編譯器在編譯時只評估一個constexpr函數,**在那些需要常量表達式的情況下,就像在上面的例子中一樣,不管它是調試還是發佈版本。 –

+0

你確定嗎?這是一個反彙編的圖像,甚至使用static_assert來確保編譯時沒有錯誤: http://imgur.com/ElPkyx3 –

+0

@DeusSum你沒有在鏈接的例子中使用VS2015,也沒有使用clang或GCC。根據C++ 14標準中的[dcl.constexpr]/9,這三個編譯器在編譯時評估函數「POW」,這正是他們應該做的。另見[this](http://eel.is/c++draft/dcl.constexpr#9)。然後,我必須得出結論,根據所提到的段落,你使用的編譯器有一個錯誤。 – Belloc

相關問題