2014-03-04 38 views
11

請參閱更新以獲得更好的問題示例。原代碼有哪些muddies圖片問題的混合:gcc是否考慮將非常量表達式函數的內置函數作爲常量表達式

這個問題Why can I call a non-constexpr function inside a constexpr function?呈現以下代碼

#include <stdio.h> 

constexpr int f() 
{ 
    return printf("a side effect!\n"); 
} 

int main() 
{ 
    char a[f()]; 
    printf("%zd\n", sizeof a); 
} 

這是我的回答是形成不良gcc 4.8.2允許它(see it live )。

但是,如果我們使用​​標誌gcc產生一個錯誤(see it live):

error: call to non-constexpr function 'int printf(const char*, ...)' 
    return printf("a side effect!\n"); 
            ^

所以seemsgcc正在考慮的printf內置版本是一個常量表達式。 gccdocuments builtins here但是沒有記錄這種情況,其中非constexpr函數的內建可以被認爲是一個常量表達式。

如果事實確實如此:

  • 是一個編譯器允許這樣做嗎?
  • 如果他們被允許,他們不需要證明它符合?
  • 可以這樣考慮的延伸,如果是這樣,好像這將需要警告的C++ draft standard部分1.4實現達標款說(重點煤礦):

A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so, however, they can compile and execute such programs.

更新

正如凱西指出有一些事情正在進行在原來的問題,使其成爲一個不好的例子。一個簡單的例子將使用std::pow其不是constexpr功能:

#include <cmath> 
#include <cstdio> 

constexpr double f() 
{ 
    return std::pow(2.0, 2.0) ; 
} 

int main() 
{ 
    constexpr double x = f() ; 

    printf("%f\n", x) ; 
} 

編譯並沒有警告或錯誤(see it live)構建但添加​​使得它產生一個錯誤(see it live)。注:why math functions are not constexpr in C++11

error: call to non-constexpr function 'double pow(double, double)' 
    return std::pow(2.0, 2.0) ; 
          ^
+2

究竟你認爲GCC違反了這裏?是不是[dcl.constexpr]/5「對於一個constexpr函數,如果沒有函數參數值存在,使得函數調用替換會產生一個常量表達式(5.19),則該程序不合格;不需要診斷。 ? – dyp

+1

注意:我不太明白gcc拒絕它時爲什麼說「gcc 4.8.2允許它」,調用'f()'是*不是一個常量表達式*。然而,它不拒絕的是函數f'本身的定義,對此AFAIK,不需要診斷。 – dyp

+0

我不相信它將內置視爲一個常量表達式。你沒有提供證明它的例子(並且調用'f()',導致調用'printf(「副作用!\ n」)*不*被認爲是一個常量表達式)。 – dyp

回答

4

GCC不考慮f()是一個常量表達式。看看診斷the first sample program you linked

main.cpp: In function 'int main()': 
main.cpp:10:19: warning: ISO C++ forbids variable length array 'a' [-Wvla] 
     char a[f()]; 
       ^

編譯器不認爲f()是一個常量表達式,該計劃實際上是在使用GCC的擴展,允許變長數組 - 數組與非固定的大小。

如果你改變了計劃,以迫使f()成一個常量表達式:

int main() { 
    constexpr int size = f(); 
    char a[size]; 
    printf("%zd\n", sizeof a); 
} 

GCC does report an error

 
main.cpp: In function 'int main()': 
main.cpp:10:32: in constexpr expansion of 'f()' 
main.cpp:5:41: error: 'printf(((const char*)"a side effect!\012"))' is not a constant expression 
     return printf("a side effect!\n"); 
             ^
+0

[這是一個更簡單](http://coliru.stacked-crooked.com/a/236de6511453a86d)用'strlen'的例子,我不得不再看另一個例子。 –

+0

@ShafikYaghmour'strlen'沒有副作用。它很可能是「constexpr」。 [考慮到這個編譯](http://coliru.stacked-crooked.com/a/fe68fdf40c91374c),我會說爲了所有目的,它*是*'constexpr'用於特殊的gcc +參數。有趣的是,C++ 1y(無論如何,N3936)17.6.5.6 [constexpr.functions]/1可能會禁止這種行爲:「本標準明確要求某些標準庫函數是constexpr(7.1.5)。實現 不應該將任何標準庫函數簽名聲明爲constexpr,除了那些明確需要它的地方。「 – Casey

+0

如果[你使用-fno-builtin](http://coliru.stacked-crooked.com/a/ec518e0424db5ef1)它會產生一個錯誤:'錯誤:調用非constexpr函數'size_t strlen(const char *)' ' –

6

是,gcc正在考慮一些builtin functionsconstexpr即使標準不明確標記爲這樣。我們可以發現,特別是涉及到在gcc bug報告[C++0x] sinh vs asinh vs constexprcmath發現數學函數,它說的討論:

LWG 2013 does seem to allow GCC to treat these functions as constexpr. So, fixed for 4.7

這是指LWG issue 2013其原來提出的決議是添加以下部分17.6.5.6[ constexpr.functions]重點煤礦前進):

[...]Additionally, an implementation may declare any function to be constexpr if that function's definition satisfies the necessary constraints[...]

但C++ 11的分辨率被推翻,後最終解決最終爲:

[...]An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required.[..]

所以這是(在C++ 14a explicitly non-conforming extension目前並儘可能我可以告訴這是不符合要求的在C++ 11,因爲它改變觀察的行爲因此將不被允許通過,如果規則

喬納森Wakely指出一個libstdc++郵件列表討論:PR libstdc++/49813 revisited: constexpr on functions (and builtins)其中重開上述討論的bug報告,由於上述佈局的問題:

I believe we should re-open the bug in light of the actual resolution of LWG 2013 (adding constexpr is forbidden).

The FE should not treat builtins as constexpr in strict-conformance mode.

We should either remove _GLIBCXX_CONSTEXPR from <cmath> entirely or make it conditional on __STRICT_ANSI__.

+1

不錯的總結。另見https://gcc.gnu.org/ml/libstdc++/2014-09/msg00004.html –