2015-12-15 77 views
18

以下代碼段在clang ++ 3.7.0下編譯,但被g ++ 5.3.1拒絕。兩者都有-std=c++14選項。哪個編譯器是正確的?任何人都知道標準會在哪裏談論這個?謝謝。在constexpr函數中投入

#include <stdexcept> 
using namespace std; 

constexpr int f(int n) { 
    if (n <= 0) throw runtime_error(""); 
    return 1; 
} 

int main() { 
    char k[f(1)]; 
} 

輸出

[hidden] g++ -std=c++14 c.cpp 
c.cpp: In function ‘constexpr int f(int)’: 
c.cpp:7:1: error: expression ‘<throw-expression>’ is not a constant-expression 
} 
^ 
[hidden] clang++ -std=c++14 c.cpp 
[hidden] 
[hidden] g++ -v 
Using built-in specs. 
COLLECT_GCC=/usr/bin/g++ 
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/lto-wrapper 
Target: x86_64-redhat-linux 
Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --disable-libgcj --with-isl --enable-libmpx --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux 
Thread model: posix 
gcc version 5.3.1 20151207 (Red Hat 5.3.1-2) (GCC) 
[hidden] 
[hidden] clang++ -v 
clang version 3.7.0 (http://llvm.org/git/clang.git 2ddd3734f32e39e793550b282d44fd71736f8d21) 
Target: x86_64-unknown-linux-gnu 
Thread model: posix 
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/3.4.6 
Found candidate GCC installation: /usr/lib/gcc/x86_64-redhat-linux/5.3.1 
Selected GCC installation: /usr/lib/gcc/x86_64-redhat-linux/5.3.1 
Candidate multilib: .;@m64 
Candidate multilib: 32;@m32 
Selected multilib: .;@m64 
+0

標準沒有按不能說它不能拋出,據我所知 –

+0

有人指出,有一個海灣合作委員會的錯誤報告,沒有提供變通。 –

回答

15

鐺是正確的,請注意HEAD revision of gcc accepts也接受此代碼。這是一個格式良好的constexpr函數,只要參數的值能讓函數被評估爲核心常量表達式。在你的情況下,1就是這樣一個值。

這是覆蓋在草案C++ 14標準部7.1.5的constexpr符[dcl.constexpr]它告訴我們什麼是允許在一個constexpr函數:

一個constexpr函數的定義應滿足以下約束:

  • 它不應該是虛擬的(10.3);

  • 它的返回類型應該是一個文字類型;

  • 它的每個參數類型應該是一個文字類型;

  • 其功能體應爲=刪除,=默認情況下,或不包含

    • 的ASM-定義的化合物語句,

    • goto語句,

    • 一個try-block,或者

    • 定義一個非文字類型的變量或靜態或線程st orage持續時間或其中 不執行初始化。

沒有限制對throw它還說(重點煤礦):

對於非模板,非違約constexpr功能或非模板,非違約,非繼承 constexpr構造函數,如果不存在任何參數值,則可以對函數或構造函數 的調用進行評估核心常量表達式(5.19)的子表達式,該程序不合格;沒有 需要診斷。

和下面這一段我們有以下的例子中,類似於你:

constexpr int f(bool b) 
    { return b ? throw 0 : 0; } // OK 
constexpr int f() { return f(true); } // ill-formed, no diagnostic required 

throw不允許在覈心常量表達式,其是覆蓋在部分5.19[expr.const ]段落2其中說:

條件表達式e是一個核心常量表達式除非e的評價,如下所述 抽象機(1.9),將評估以下表達式

中的一個的規則,幷包括以下子彈:

  • 一個投擲表達式(15.1)。

f不會在覈心常量表達式時n <= 0是可用的。

更新

由於TemplateRex指出,對於這種兩個GCC的bug報告:

TemplateRex還注意到,修復不適用到5.3.0,只在後備箱。不,提供解決方法。

4

Shafik Yaghmour所示,這是一個gcc錯誤,希望在v6中修正。

在那之前,你可以恢復到c++11 constexpr風格:

constexpr auto foo(int n) -> int 
{ 
    return n <= 0 ? throw runtime_error("") : 1; 
} 

但是有一個更好的解決辦法,仍保留所有c++14 constexpr擴展:

// or maybe name it 
// throw_if_zero_or_less 
constexpr auto foo_check_throw(int n) -> void 
{ 
    n <= 0 ? throw std::runtime_error("") : 0; 
} 

constexpr auto foo(int n) -> int 
{ 
    foo_check_throw(n); 

    // C++14 extensions for constexpr work: 
    if (n % 2) 
    return 1; 
    return 2; 
}