2016-04-11 33 views
0

Aşağıdaki kod parçasını this comment'dan @CaffeineAddict tarafından aldım. VS2015 elde edilen aşağıdaki sökme ileDerleyici, derleme zamanında değerlendirmek yerine `POW` işlevini çağırmaya karar verdi. Niye ya?

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

:

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 
} 

gösterileri derleyici Öldü diye ki (demontaj bana getirdiği karakterleri "< < ======" bölümüne bakınız) hangi t derleme zamanında POW işlevini değerlendirin. Onun yorumuna göre, @CaffeineAddict bu davranışı derleyiciden beklemekteydi. Ama hala bunun neden beklenen olduğunu hala anlayamıyorum?

+1

Nedir bu ** siz ** bekliyorsunuz? Derleyiciden derleme zamanında değerlendirmesini hiç istemediniz. (başlığınız sorunun gövdesiyle çelişiyor gibi görünmektedir ...) –

+0

@MarcGlisse "POW" işlevi "constexpr" işlevidir ve sürekli ifadelerle çağrılmaktadır. Başlığı yeni düzenledim. İlgimi çektiğin için teşekkürler. –

+0

Hata ayıklama oluşturma koduna bakma gen, hiçbir zaman çok kullanışlı değildir. Const auto değerini kullan = POW (2, 63); Derleyiciyi yapmak istediğiniz şeyi yapmaya zorlamak ve mutlu bir sonucu garanti etmek için. Bunun neden garantiyi geçersiz kıldığını kavrayın (2, -1) yerine :) –

cevap

0

İki neden.

İlk olarak, bir derleme işlevinin derleme zamanında çağrılması garanti edilmez. derleme anında çağırmak için derleyici zorlamak için, size Yayın yapılandırmasında proje oluşturmalısınız, İkincisi, ilk olarak bir constexpr değişkende yani

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

saklayın gerekir. VS'te, projeyi Debug yapılandırması kullanarak oluşturduysanız, Constexpr işlevlerini kesebileceğinizi göreceksiniz.

+0

VS2015 derleyicisinin, derleme zamanında ** sadece ** bir constexpr işlevini değerlendirdiği anlaşılıyor. Bu durumda, yukarıdaki örnekte olduğu gibi, sabit bir ifadenin gerekli olduğu durumlarda, bir hata ayıklama veya yayın oluşturma yapılıp yapılmadığından bağımsız olarak. –

+0

Bundan emin misin? Burada, derleme zamanı hakkında bir hata olmadığından emin olmak için static_assert kullanarak bile demontaj görüntüsü: http://imgur.com/ElPkyx3 –

+0

@DeusSum Bağlantılı örnekte VS2015 kullanmadınız, clang veya GCC. Üç derleyici, "POW" işlevini derleme zamanında değerlendirir ve bu, C++ 14 Standardındaki [dcl.constexpr]/9'a göre yapmaları gereken şeydir. Ayrıca bakınız [this] (http://eel.is/c++draft/dcl.constexpr#9). Ardından, kullandığınız derleyicinin aldatılmış paragrafa göre bir hata olduğu sonucuna varmalıyım. – Belloc