Throw in constexpr function

后端 未结 2 914
被撕碎了的回忆
被撕碎了的回忆 2020-11-30 12:25

The following piece of code compiles under clang++ 3.7.0 but is denied by g++ 5.3.1. Both have -std=c++14 option. Which compiler is correct? Anyone knows whe

相关标签:
2条回答
  • 2020-11-30 13:05

    clang is correct, note the HEAD revision of gcc accepts also accepts this code. This is a well-formed constexpr function, as long as there is value for the argument(s) that allows the function to be evaluated as a core constant expression. In your case 1 is such a value.

    This is covered in the draft C++14 standard section 7.1.5 The constexpr specifier [dcl.constexpr] which tells us what is allowed in a constexpr function:

    The definition of a constexpr function shall satisfy the following constraints:

    • it shall not be virtual (10.3);

    • its return type shall be a literal type;

    • each of its parameter types shall be a literal type;

    • its function-body shall be = delete, = default, or a compound-statement that does not contain

      • an asm-definition,

      • a goto statement,

      • a try-block, or

      • a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed.

    no restriction on throw and it also says (emphasis mine):

    For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required.

    and below this paragraph we have the following example, similar to yours:

    constexpr int f(bool b)
      { return b ? throw 0 : 0; } // OK
    constexpr int f() { return f(true); } // ill-formed, no diagnostic required
    

    throw is not allowed in a core constant expression, which is covered in section 5.19 [expr.const] paragraph 2 which says:

    A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions

    and includes the following bullet:

    • a throw-expression (15.1).

    and so f would not be usable in a core constant expression when n <= 0.

    Update

    As TemplateRex points out, there are two gcc bugs reports for this:

    • Never executed "throw" in constexpr function fails to compile
    • C++14] throw-expression is not a valid constant-expression

    TemplateRex also notes the fixes are not applied to to 5.3.0 and are only in trunk. No, work arounds are provided.

    0 讨论(0)
  • 2020-11-30 13:05

    As shown by Shafik Yaghmour it's a gcc bug, which is fixed in v6.1

    If you are still using the old gcc version you can revert to the c++11 constexpr style:

    constexpr auto foo(int n) -> int
    {
      return n <= 0 ? throw runtime_error("") : 1;
    }
    

    However there is a better workaround, still retaining all of the c++14 constexpr extensions:

    // 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;
    }
    
    0 讨论(0)
提交回复
热议问题