yohhoyの日記

技術的メモをしていきたい日記

定数式中でのconstexpr関数はnoexcept指定相当

2020-08-13追記:C++17で言語仕様が調整され、constexpr関数であってもnoexceptは特別扱いされなくなった。詳細は c++ - `noexcept` behavior of `constexpr` functions - Stack Overflow 参照のこと。

定数式(constant expression)中で呼び出すconstexpr関数は、noexcept指定がされているかのように振る舞う。ただし未定義constexpr関数の呼び出しや、非定数式コンテキストからのconstepxr関数呼び出しは、同ルールの適用外となる。

// C++14
constexpr int f() { return 0; }
constexpr int g();  // 宣言のみ
static_assert( noexcept(f()), "noexcept(f()) shall be true");
static_assert(!noexcept(g()), "noexcept(g()) shall be false");

constexpr int h(bool b) { return b ? 0 : throw 42; }
static_assert( noexcept(h(true)),  "noexcept(h(T)) shall be true");
static_assert(!noexcept(h(false)), "noexcept(h(F)) shall be false");

#include <iostream>
int main()
{
  std::cout << std::boolalpha;
  std::cout << noexcept(h(true));  // true
  bool b = true;
  std::cout << noexcept(h(b));     // false
}

上記コードはgccだと期待通り動作するが、Clangは3.6.0現在でも未対応のためコンパイルエラーとなる。

C++11 5.3.7/p3, 5.19/p2より一部引用(下線部は強調)。

3 The result of the noexcept operator is false if in a potentially-evaluated context the expression would contain

  • a potentially evaluated call to a function, member function, function pointer, or member function pointer that does not have a non-throwing exception-specification (15.4), unless the call is a constant expression (5.19),
  • (snip)

Otherwise, the result is true.

2 A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [Note: An overloaded operator invokes a function. -- end note]:

  • (snip)
  • an invocation of an undefined constexpr function or an undefined constexpr constructor outside the definition of a constexpr function or a constexpr constructor;
  • (snip)
  • a throw-expression (15.1).

関連URL