抛出constexpr功能

时间:2015-12-15 03:38:59

标签: c++ gcc c++14 constexpr

以下代码在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

2 个答案:

答案 0 :(得分:20)

clang是正确的,请注意HEAD revision of gcc accepts也接受此代码。这是一个格式良好的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] 段{{1}其中说:

  

条件表达式e是核心常量表达式,除非e的评估遵循规则   抽象机器(1.9),将评估以下表达式之一

并包含以下项目符号:

  
      
  • 一个throw-expression(15.1)。
  •   

因此2f在核心常量表达式中不可用。

更新

正如TemplateRex指出的那样,有两个gcc错误报告:

TemplateRex还注意到修补程序未应用于n <= 0并且仅在主干中。不,提供解决方法。

答案 1 :(得分:6)

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;
}