N3597 Relaxing constraints on constexpr functions
N3598 constexpr member functions and implicit const
N3652 Relaxing constraints on constexpr functions
C++14では、constexpr関数の制限がいくつか緩和されます。
緩和されるリストは、以下になります:
- 変数宣言の許可
- if文とswitch文の許可
- 全てのループ文の許可(for、範囲for、while、do-while)
- 変数書き換えの許可
- 戻り値型(リテラル型)として、voidを許可
- 追加として、constexpr非静的メンバ関数の暗黙のconst修飾を削除
変数宣言の許可
constexpr int f() { int result = 0; // OK // 関数f()自体がconstexprであるため、 // 変数resultはconstexprである必要はない。 return result; }
ただし、以下の制限があります:
- staticやthread_localといった記憶域の指定はできません
- 未初期化変数の宣言はできません
if文とswitch文の許可
constexpr int abs(int x) { if (x < 0) // OK return -x; return x; }
enum class Weekday { Sun, Mon, Tue, }; constexpr Weekday intToWeekday(int n) { switch (n) { // OK case 0: return Weekday::Sun; case 1: return Weekday::Mon; case 2: return Weekday::Tue; } throw std::out_of_range("n is out of week"); }
ただし、条件分岐としてgoto文は許可されません。
全てのループ文の許可
constexpr int f() { int x = 0; // OK : for文 for (int i = 0; i < 5; ++i) { x += i + 1; } // OK : 範囲for文 int ar[] = {6, 7, 8}; for (const int& i : ar) { x += i; } // OK : while文 while (true) { x += 9; break; } // OK : do-while文 do { x += 10; } while (false); return x; }
for文、範囲for文、while文、do-while文が許可されます。
さて、returnする値はいくつでしょうか?
変数書き換えの許可
constexpr int square(int x) { x *= x; // OK : 変数は書き換えてもよい return x; }
struct X { int x; constexpr X(int x) : x(x) {} constexpr int square() { x *= x; // OK : メンバ変数も書き換えられる return x; } }; constexpr int square(int n) { X x(n); return x.square(); }
書き換えられるのはconstexpr変数だけなので、グローバル変数のerrnoとかは書き換えられません。
戻り値型としてvoidを許可
constexpr void square(int& x) { x *= x; } constexpr int f(int x) { square(x); return x; }
constexprとして扱える型分類である「リテラル型(literal type)」にvoidが追加されます。
これを使用して、参照パラメータを書き換えて返すスタイルが可能になります。
constexpr非静的メンバ関数の暗黙のconst修飾を削除
struct X { constexpr int f(); // C++11では以下と同じ // constexpr int f() const; };
C++11では、constexprメンバ関数は、暗黙にconst修飾されていました。このため、明示的なconst修飾ができませんでした。
C++14ではこの仕様が廃止され、const修飾は明示的に行うことになり、constと非constでオーバーロードが可能になります。