下面的代码在clang ++ 3.7.0下编译,但被g ++ 5.3.1拒绝.两者都有-std=c++14
选择权.哪个编译器正确?有谁知道标准在哪里谈论这个?谢谢.
#includeusing 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 ‘’ 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
Shafik Yaghm.. 22
clang是正确的,注意gcc接受的HEAD修订也接受这个代码.这是一个格式良好的constexpr函数,只要参数的值允许将函数计算为核心常量表达式.在你的情况下1
是这样的价值.
这在C++ 14标准草案章节7.1.5
constexpr说明符[dcl.constexpr]中有所介绍,它告诉我们constexpr函数允许的内容:
constexpr函数的定义应满足以下约束:
它不应是虚拟的(10.3);
其返回类型应为字面类型;
每个参数类型都应是文字类型;
它的函数体应为= delete,= default或不包含的复合语句
asm-definition,
一个goto声明,
尝试块,或
非文字类型或静态或线程存储持续时间的变量的定义,或者不执行初始化的定义.
没有限制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是核心常量表达式,除非根据抽象机器(1.9)的规则评估e将评估以下表达式之一
并包括以下项目:
一个throw-expression(15.1).
因此f
,当核心常量表达式不可用时n <= 0
.
更新
正如TemplateRex指出的那样,有两个gcc错误报告:
从未在constexpr函数中执行"throw"无法编译
C++ 14] throw-expression不是一个有效的常量表达式
TemplateRex还注意到修复程序不适用于5.3.0
且仅适用于主干.不,提供工作.
clang是正确的,注意gcc接受的HEAD修订也接受这个代码.这是一个格式良好的constexpr函数,只要参数的值允许将函数计算为核心常量表达式.在你的情况下1
是这样的价值.
这在C++ 14标准草案章节7.1.5
constexpr说明符[dcl.constexpr]中有所介绍,它告诉我们constexpr函数允许的内容:
constexpr函数的定义应满足以下约束:
它不应是虚拟的(10.3);
其返回类型应为字面类型;
每个参数类型都应是文字类型;
它的函数体应为= delete,= default或不包含的复合语句
asm-definition,
一个goto声明,
尝试块,或
非文字类型或静态或线程存储持续时间的变量的定义,或者不执行初始化的定义.
没有限制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是核心常量表达式,除非根据抽象机器(1.9)的规则评估e将评估以下表达式之一
并包括以下项目:
一个throw-expression(15.1).
因此f
,当核心常量表达式不可用时n <= 0
.
更新
正如TemplateRex指出的那样,有两个gcc错误报告:
从未在constexpr函数中执行"throw"无法编译
C++ 14] throw-expression不是一个有效的常量表达式
TemplateRex还注意到修复程序不适用于5.3.0
且仅适用于主干.不,提供工作.
如Shafik Yaghmour所示,它是一个gcc bug,希望在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; }