2016-04-11 2 views
0

Ich habe das Snippet unten von this comment von @CaffeineAddict.Der Compiler entschied sich dafür, die Funktion "POW" aufzurufen, anstatt sie zur Kompilierzeit auszuwerten. Warum?

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

mit folgenden Demontage von VS2015 erhalten:

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 
} 

, die zeigt (siehe die Zeichen "< < ======" eingeführt, die von mir in der Demontage), dass der Compiler didn‘ t Bewerten Sie die Funktion POW zur Kompilierzeit. Von seinem Kommentar schien @CaffeineAddict dieses Verhalten vom Compiler zu erwarten. Aber ich kann immer noch nicht verstehen, warum das überhaupt erwartet wurde?

+1

Was hast du erwartet **? Sie haben den Compiler nie aufgefordert, ihn zur Kompilierungszeit auszuwerten. (Ihr Titel scheint dem Körper der Frage zu widersprechen ...) –

+0

@MarcGlisse Die Funktion 'POW' ist' constexpr' und wird mit konstanten Ausdrücken aufgerufen. Ich habe gerade den Titel bearbeitet. Danke, dass du meine Aufmerksamkeit geweckt hast. –

+0

Der Debug-Build-Code gen ist nie sehr nützlich. Verwenden Sie const auto value = POW (2, 63); um den Compiler zu zwingen, das zu tun, was Sie tun wollen und ein glückliches Ergebnis zu garantieren. Erhalten Sie einen Einblick, warum dies die Garantie ungültig macht, indem Sie stattdessen (2, -1) übergeben: –

Antwort

0

Zwei Gründe.

Erstens kann eine constexpr -Funktion nicht zur Kompilierzeit aufgerufen werden. Um den Compiler zu zwingen sie zum Zeitpunkt der Kompilierung zu nennen, müssen Sie es in einer constexpr Variablen speichern erste, das heißt

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

Zweitens müssen Sie das Projekt in Release-Konfiguration aufzubauen. In VS werden Sie feststellen, dass Sie conetexpr-Funktionen durchbrechen können, wenn Sie das Projekt mithilfe der Debug-Konfiguration erstellt haben.

+0

Es scheint, als würde der VS2015-Compiler eine conetexpr-Funktion nur zur Kompilierzeit ** in den Situationen evaluieren, in denen ein konstanter Ausdruck erforderlich ist, wie in obigem Beispiel, unabhängig davon, ob es sich um einen Debug- oder einen Release-Build handelt. –

+0

Sind Sie sicher? Hier ist ein Bild der Disassemblierung, auch mit static_assert, um sicherzustellen, dass es keine Kompilierungszeit ist: http://imgur.com/ElPkyx3 –

+0

@DeusSum Sie haben VS2015 im verknüpften Beispiel nicht verwendet, noch clang oder GCC. Die drei Compiler evaluieren die Funktion 'POW' zur Kompilierzeit, und das ist genau das, was sie nach [dcl.constexpr]/9 im C++ 14 Standard tun sollen. Siehe auch [dies] (http://eel.is/c++draft/dcl.constexpr#9). Dann muss ich schlussfolgern, dass der Compiler, den Sie verwenden, einen Fehler hat, gemäß dem erwähnten Absatz. – Belloc

Verwandte Themen