再加上constexpr功能再加上constexpr功能(Throw in constexpr fu

2019-05-12 07:31发布

下面的代码段下铛++ 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

Answer 1:

铛是正确的,请注意GCC的HEAD修订接受也接受此代码。 这是一个结构良好constexpr功能,只要存在用于参数(多个),其允许函数来作为芯常量表达式被评估值。 在你的情况1是这样的一个值。

这是包括在草案C ++ 14标准节7.1.5的constexpr符[dcl.constexpr]它告诉我们什么是允许在constexpr功能:

一个constexpr函数的定义应满足以下约束条件:

  • 它不得虚拟(10.3);

  • 它的返回类型应该是一个文本类型;

  • 它的每个参数类型应是一个文本类型;

  • 其功能体应=删除,=默认值,或不包含复合语句

    • 的ASM-定义,

    • goto语句,

    • try块,或

    • 非文字类型或静态或线程存储持续时间或针对其执行没有初始化的变量的定义。

没有限制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报告:

  • 永远不会执行“扔”在constexpr函数编译失败
  • C ++ 14]界外球表达不是有效的常数表达式

TemplateRex还指出,修复不适用于对5.3.0 ,并且仅在行李箱中。 不,提供了变通。



Answer 2:

如图沙菲克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;
}


文章来源: Throw in constexpr function