2015-12-15 81 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; 
}