Throw in constexpr function

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.


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.

Leave a Comment