插入constexpr函数
Throw in constexpr function
以下代码在clang++3.7.0下编译,但被g++5.3.1拒绝。两者都有-std=c++14
选项。哪个编译器是正确的?有人知道标准中在哪里谈论这件事吗?谢谢
#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
clang是正确的,注意gcc accept的HEAD修订版也接受此代码。这是一个格式良好的constexpr函数,只要参数的值允许将函数作为核心常量表达式进行计算。在您的情况下,1
就是这样一个值。
这在草案C++14标准部分7.1.5
中介绍。constexpr说明符[dcl.constexpr]告诉我们constexpr函数中允许的内容:
constexpr函数的定义应满足以下约束:
它不应是虚拟的(10.3);
其返回类型应为文字类型;
其每个参数类型应为文字类型;
其函数体应为=删除、=默认或不包含的复合语句
asm定义,
goto声明
试块,或
非文字类型变量、静态变量或线程存储持续时间变量的定义不执行初始化。
对throw
没有限制,它还说(emphasis mine):
对于非模板、非默认的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),将评估以下表达式之一
包括以下项目符号:
- 抛出表达式(15.1)
因此CCD_ 8在CCD_。
更新
正如TemplateRex所指出的,有两个gcc错误报告:
- constexpr函数中从未执行过的"throw"无法编译
- C++14]throw表达式不是有效的常量表达式
TemplateRex还指出,这些修复程序并没有应用于5.3.0
,只在trunk中。不,提供了解决方案。
如Shafik Yaghmour所示,这是一个gcc错误,已在v6.1 中修复
如果您仍在使用旧的gcc版本,则可以恢复到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;
}
- 条件constexpr函数
- constexpr 函数中的非文字(通过 std::is_constant_evaluated)
- constexpr构造函数需要常量成员函数时出现问题
- constexpr 函数获取常量字符*
- 如何在 constexpr 函数中实现回退运行时
- 为什么我不能在 constexpr lambda 函数中使用 std::tuple
- 在非 constexpr 函数中作为左值传递的变量上使用 'constexpr' 函数
- 在 constexpr 构造函数 (c++17) 中赋值到 const char * 在使用 Android NDK 时
- NVCC 错误:string_view.h:constexpr 函数返回是非常量
- constexpr函数中的静态constexpr变量
- 在 constexpr funnction 中调用basic_string函数
- 为什么我的 constexpr 对象在我的函数中不是 constexpr?
- constexpr log10 整数函数
- C++:初始化 constexpr 构造函数中的成员数组
- 编译器生成的默认构造函数具有 constexpr 混淆行为
- 在 constexpr 构造函数中初始化数组是否合法?
- 在 constexpr 函数中断言
- MSVC 和函数参数的 constexpr?
- 具有位域的结构的 Constexpr 构造函数
- C++ 默认构造函数 constexpr 或正确未定义