Constant expressions
コンパイル時に評価可能な expression を定義します。
このような式は、定数テンプレート引数、配列サイズ、およびその他の定数式を必要とする文脈で使用できます。例えば、
int n = 1; std::array<int, n> a1; // エラー: 「n」は定数式ではありません const int cn = 2; std::array<int, cn> a2; // OK: 「cn」は定数式です
目次 |
定義
|
以下の定数式カテゴリのいずれかに属する式は 定数式 です。
|
(C++11以前) | ||
|
以下の式は総称して constant expressions (定数式)と呼ばれる:
|
(C++11以降)
(C++14まで) |
||
|
以下のエンティティは 定数式の許可された結果 です:
定数式 とは、定数式の許可された結果であるエンティティを参照するglvalue コア定数式 であるか、または値が以下の制約を満たすprvalueコア定数式のいずれかです:
|
(C++14以降)
(C++26まで) |
||
|
定数式 は、オブジェクトまたは非 即時関数 を参照するglvalue コア定数式 、またはその値が以下の制約を満たすprvalueコア定数式のいずれかである:
|
(C++26以降) |
式が定数式かどうかを判定する際、 copy elision は実行されないものと仮定されます。
C++98における定数式の定義は折りたたみボックス内に完全に含まれています。以下の説明はC++11以降のC++バージョンに適用されます。
リテラル型
以下の型はまとめて literal types と呼ばれます:
-
- これは trivial destructor (until C++20) constexpr destructor (since C++20) を持ちます。
- すべての非静的non-variantデータメンバと基底クラスが非volatileリテラル型です。
- 以下のいずれかの型です:
| (C++17以降) |
リテラル型のオブジェクトのみが定数式内で作成できます。
コア定数式
core constant expression は、以下の言語構成のいずれかを評価 しない 式の評価のことです:
| 言語構成要素 | バージョン | 論文 |
|---|---|---|
this
ポインタ、ただし式の一部として評価されている
constexpr
関数
内、または暗黙的・明示的なクラスメンバアクセス式に現れる場合を除く
|
N2235 | |
| 静的またはスレッド ストレージ期間 を持つ ブロック変数 の宣言を通り抜ける制御フローで、その変数が 定数式で使用可能でない 場合 | (C++23以降) | P2242R3 |
|
このセクションは不完全です
理由:以下のraw-HTML順序付きリストの内容を上のwikitableに転記し、対応する項目を標準に導入した論文/CWGイシューを追加してください。ミニ例は保持されません。これらはこのページの下部で大きな例を形成するために結合できます。 |
-
a function call expression that calls a function (or a constructor) that is not declared
constexpr
constexpr int n = std::numeric_limits<int>::max(); // OK: max() は constexpr constexpr int m = std::time(nullptr); // エラー: std::time() は constexpr ではない
- a function call to a constexpr function which is declared, but not defined
- a function call to a constexpr function/constructor template instantiation where the instantiation fails to satisfy constexpr関数/コンストラクタ requirements.
- a function call to a constexpr virtual function, invoked on an object whose dynamic type is constexpr-unknown
- an expression that would exceed the implementation-defined limits
-
an expression whose evaluation leads to any form of core language
undefined
または誤った
(C++26以降)
behavior, except for any potential undefined behavior introduced by
標準属性
.
constexpr double d1 = 2.0 / 1.0; // OK constexpr double d2 = 2.0 / 0.0; // エラー: 未定義 constexpr int n = std::numeric_limits<int>::max() + 1; // エラー: オーバーフロー int x, y, z[30]; constexpr auto e1 = &y - &x; // エラー: 未定義 constexpr auto e2 = &z[20] - &z[3]; // OK constexpr std::bitset<2> a; constexpr bool b = a[2]; // 未定義動作、検出されるかどうかは未指定
- (C++17まで) a ラムダ式
-
an lvalue-to-rvalue
暗黙の変換
unless applied to...
- (possibly cv-qualified) 型の glvalue である std::nullptr_t
-
定数式で使用可能なオブジェクトを指す、非 volatile リテラル型の glvalue
usable in constant expressions
int main() { const std::size_t tabsize = 50; int tab[tabsize]; // OK: tabsize is a constant expression // because tabsize is usable in constant expressions // because it has const-qualified integral type, and // its initializer is a constant initializer std::size_t n = 50; const std::size_t sz = n; int tab2[sz]; // Error: sz is not a constant expression // because sz is not usable in constant expressions // because its initializer was not a constant initializer }
- この式の評価内で生存期間が開始された非 volatile オブジェクトを参照する、非 volatile リテラル型の glvalue
T*
ポインタがヌルポインタ値を保持しているか、またはその型が
similar
であるオブジェクトを指していない限り
T
(since C++26)
dynamic_cast
オペランドがconstexpr-unknownな動的型を持つオブジェクトを参照するglvalueである
(C++20以降)
reinterpret_cast
constexpr int incr(int& n) { return ++n; } constexpr int g(int k) { constexpr int x = incr(k); // エラー: incr(k) はコア定数式ではない // k の寿命が incr(k) 式の外側で // 始まっているため return x; } constexpr int h(int k) { int x = incr(k); // OK: x はコア定数式で初期化される // 必要はない return x; } constexpr int y = h(1); // OK: y を値 2 で初期化する // h(1) はコア定数式である。なぜなら // k の寿命が式 h(1) の内側で始まるため
typeid
expression applied to a glvalue of polymorphic type
そのglvalueがconstexpr-unknownな動的型を持つオブジェクトを参照している場合
(C++20以降)
|
(C++20以降) |
|
(C++26以降) |
constexpr void check(int i) { if (i < 0) throw i; } constexpr bool is_ok(int i) { try { check(i); } catch (...) { return false; } return true; } constexpr bool always_throw() { throw 12; return true; } static_assert(is_ok(5)); // OK static_assert(!is_ok(-1)); // C++26からOK static_assert(always_throw()); // エラー: キャッチされない例外
goto
文
dynamic_cast
または
typeid
式
または
new
式
(C++26から)
が例外をスローする場合
例外型の定義が到達可能でない場合
(C++26から)
void g() { const int n = 0; constexpr int j = *&n; // OK: ラムダ式の外側 [=] { constexpr int i = n; // OK: 'n'はここではodr-usedされず、キャプチャもされない constexpr int j = *&n; // 不適格: '&n'は'n'のodr-useとなる }; }
|
odr-useがクロージャの関数呼び出しで行われる場合、それは this または外側の変数を参照しないことに注意(代わりにクロージャのデータメンバにアクセスするため) // OK: 'v' & 'm'はodr-usedされるが、ネストしたラムダ内の定数式では現れない // ネストしたラムダ内の定数式では現れない auto monad = [](auto v){ return [=]{ return v; }; }; auto bind = [](auto m){ return [=](auto fvm){ return fvm(m()); }; }; // 定数式評価中に作成された自動オブジェクトへのキャプチャはOK static_assert(bind(monad(2))(monad)() == monad(2)()); |
(C++17から) |
追加要件
式 E が上記のいずれにも該当しない場合でも、 E の評価が runtime-undefined behavior を引き起こす場合、 E がコア定数式であるかどうかは実装定義である。
式 E が上記のいずれも評価しない場合でも、 E の評価によって以下のいずれかが評価される場合、 E がコア定数式であるかどうかは未規定です:
- 標準ライブラリにおける未定義動作の操作。
- va_start マクロの呼び出し。
式がコア定数式であるかどうかを判定する目的において、
std::
allocator
<
T
>
のメンバ関数の本体の評価は、
T
がリテラル型である場合には無視されます。
式がコア定数式であるかどうかを判定する目的において、トリビアルなコピー/ムーブコンストラクタまたはコピー/ムーブ代入演算子の呼び出しの評価は、 union のアクティブなメンバ(存在する場合)をコピー/ムーブすると見なされます。
|
式がコア定数式であるかどうかを判定する目的において、 構造化バインディング bd を名前とする識別子式の評価は以下の意味論を持つ:
|
(C++26以降) |
式をコア定数式として評価する際、すべての識別子式および * this の使用で、そのオブジェクトまたは参照の寿命が式の評価の外側で始まったものを参照するものは、そのオブジェクトまたは参照の特定のインスタンスを参照するものとして扱われ、その寿命およびすべての部分オブジェクト(すべての共用体メンバーを含む)の寿命が定数評価全体を含むものとみなされます。
- そのようなオブジェクトが 定数式で使用可能 でない場合 (C++20以降) 、そのオブジェクトの動的型は constexpr-unknown となる。
- そのような参照が 定数式で使用可能でない場合 (C++20以降) 、その参照は、参照される型の不特定オブジェクトにバインドされているものとして扱われる。このオブジェクトとそのすべての部分オブジェクトの寿命は定数評価全体を含み、動的型はconstexpr-unknownである。
整数定数式
整数定数式 は、整数型またはスコープなし列挙型の式がprvalueに暗黙的に変換されたもので、変換された式がコア定数式であるものを指します。
クラス型の式が整数定数式が期待される文脈で使用される場合、その式は 文脈に応じた暗黙変換 によって整数型またはスコープなし列挙型へ変換されます。
変換済み定数式
変換済み定数式
は、型
T
への
暗黙変換
が施された式であり、変換後の式が定数式であり、かつ暗黙変換シーケンスが以下のみを含む場合を指します:
-
- constexpr ユーザー定義変換
- 左辺値から右辺値への変換
- 整数プロモーション
- 非縮小 整数変換
- 浮動小数点プロモーション
- 非縮小 浮動小数点変換
| (C++17以降) |
また、いずれかの reference binding が行われる場合、それは direct binding のみとなります。
以下のコンテキストでは変換された定数式が必要です:
| (C++14以降) | |
|
(C++26以降) |
型 bool の文脈的に変換された定数式 は、 bool へ文脈的に変換された 式であり、変換後の式が定数式であり、変換シーケンスが上記の変換のみを含むものです。
以下の文脈では、型 bool の文脈的に変換された定数式が必要です:
| (C++23まで) | |
|
(C++17以降)
(C++23まで) |
|
| (C++20以降) |
構成要素オブジェクト obj の 構成値 は以下のように定義される:
オブジェクト obj の 構成参照 は以下の参照を含む:
変数 var の 構成値 と 構成参照 は以下のように定義される:
変数 var の任意の構成参照 ref について、 ref が一時オブジェクトまたはその部分オブジェクトにバインドされており、その生存期間が ref に 延長 されている場合、その一時オブジェクトの構成値と構成参照も再帰的に var の構成値と構成参照となる。 constexpr表現可能なエンティティ静的記憶域期間を持つオブジェクトは、プログラム内の任意の時点で constexpr参照可能 である。
自動記憶域期間を持つオブジェクト
obj
は、点
オブジェクトまたは参照
x
が点
|
(C++26以降) | ||||||||
定数初期化されたエンティティ
定数式で使用可能変数は、それが constexpr 変数 である場合、または参照型もしくは非volatileのconst修飾された整数型または列挙型である場合、 潜在的定数 となります。
定数初期化された潜在的に定数の変数
var
は、点
明示的に定数評価される式以下の式(変換先の型への変換を含む)は manifestly constant-evaluated です:
評価が明示的に定数評価されるコンテキストで行われるかどうかは、
std::is_constant_evaluated
および
|
(C++20以降) |
定数評価に必要な関数と変数
以下の式または変換は 潜在的に定数評価される 可能性があります:
- 明示的に定数評価される式
- 潜在的に評価される式
- 波括弧で囲まれた初期化子リスト の直接の部分式 ( 変換が縮小変換かどうかを判定する ために定数評価が必要な場合がある)
- テンプレート化されたエンティティ 内で現れるアドレス取得式 (そのような式が 値依存 かどうかを判定するために定数評価が必要な場合がある)
- 上記のいずれかの部分式であって、ネストされた 未評価オペランド の部分式ではないもの
関数は、constexpr関数であり、かつ定数評価される可能性のある式によって 名前が参照される 場合に、 定数評価のために必要 とされます。
変数は、それがconstexpr変数であるか、非volatileのconst修飾整数型または参照型であり、それを表す 識別子式 が定数評価される可能性がある場合、 定数評価に必要 とされます。
デフォルト化された関数の定義および 関数テンプレート 特殊化 または 変数テンプレート 特殊化 (C++14以降) のインスタンス化は、定数評価のためにその関数 または変数 (C++14以降) が必要とされる場合にトリガーされます。
定数部分式
定数部分式 とは、式 e の 部分式 として評価された場合に、 e が コア定数式 であることを妨げない式のことです。ただし、 e は以下のいずれかの式ではないものとします:
| (C++20以降) |
注記
| 機能テストマクロ | 値 | 標準 | 機能 |
|---|---|---|---|
__cpp_constexpr_in_decltype
|
201711L
|
(C++20)
(DR11) |
定数評価に必要な場合の関数と変数定義の生成 定数評価に必要な関数と変数 |
__cpp_constexpr_dynamic_alloc
|
201907L
|
(C++20) | constexpr 関数内での動的ストレージ期間操作 |
__cpp_constexpr
|
202306L
|
(C++26) | constexpr キャスト( void * からの変換):constexpr型消去に向けて |
202406L
|
(C++26) | constexpr 配置 new および new [ ] | |
__cpp_constexpr_exceptions
|
202411L
|
(C++26) | constexpr 例外: [1] 、 [2] |
例
|
このセクションは不完全です
理由: 例がありません |
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| CWG 94 | C++98 |
算術定数式は変数と静的データメンバを
含むことができなかった |
含むことができるようになった |
| CWG 366 | C++98 |
文字列リテラルを含む式
は整数定数式になり得た |
それらは該当しない |
| CWG 457 | C++98 |
volatile変数を含む式
が整数定数式になり得た |
それらは整数定数式ではない |
| CWG 1293 | C++11 |
文字列リテラルが定数式で使用可能かどうかが不明確であった
|
使用可能である |
| CWG 1311 | C++11 | volatile glvalues could be used in constant expressions | prohibited |
| CWG 1311 | C++11 | volatile glvaluesを定数式で使用可能であった | 禁止 |
| CWG 1312 | C++11 |
reinterpret_cast
は定数式では禁止されているが、
void * との間のキャストで同じ効果が達成可能 |
禁止された変換
型 cv void * から オブジェクト型へのポインタ型 |
| CWG 1313 | C++11 |
未定義動作が許可されていた;
全てのポインタ減算が禁止されていた |
UB禁止; 同一配列内の
ポインタ減算は許可 |
| CWG 1405 | C++11 |
定数式で使用可能なオブジェクトについて、
そのmutableな部分オブジェクトも使用可能であった |
使用不可となった |
| CWG 1454 | C++11 |
constexpr関数を介した参照経由での定数の受け渡しは許可されていなかった
参照経由での定数の受け渡し |
許可 |
| CWG 1455 | C++11 | 変換済み定数式はprvalueのみ可能であった | lvalueも可能 |
| CWG 1456 | C++11 |
アドレス定数式は配列の終端を1つ超えたアドレスを
指定できなかった |
許可された |
| CWG 1535 | C++11 |
a
typeid
式のオペランドが多態クラス型の場合、
ランタイムチェックが含まれない場合でも コア定数式ではなかった |
オペランドの制約は
多態クラス型の グローバル値に限定される |
| CWG 1581 | C++11 |
定数評価に必要な関数は
定義またはインスタンス化が必須ではなかった |
必須 |
| CWG 1613 | C++11 |
コア定数式はラムダ式内の任意の
odr-used参照を評価可能であった |
一部の参照は
評価できなかった |
| CWG 1694 | C++11 |
静的ストレージ期間を持つ参照への一時オブジェクトの値のバインドは定数式であった
|
これは定数式ではない
|
| CWG 1872 | C++11 |
コア定数式が
constexpr
関数テンプレートのインスタンス化を呼び出せる可能性があった
そのインスタンス化は constexpr 関数の要件を満たさない |
そのようなインスタンス化は
呼び出せない |
| CWG 1952 | C++11 |
標準ライブラリの未定義動作
は診断が要求されていた |
診断されるかどうかは
未規定 |
| CWG 2022 | C++98 |
定数式の判定がコピー省略が行われるかどうかに
依存する可能性がある |
コピー省略は常に
行われると仮定する |
| CWG 2126 | C++11 |
const修飾されたリテラル型の定数初期化された寿命延長された一時オブジェクトが
定数式で使用できなかった |
使用可能 |
| CWG 2129 | C++11 | 整数リテラルは定数式ではなかった | 定数式である |
| CWG 2167 | C++11 |
評価内のローカルな非メンバー参照
が評価を非constexprにした |
非メンバー
参照が許可される |
| CWG 2278 | C++98 | CWG issue 2022 の解決は実装不可能であった |
コピー省略は
決して実行されないと仮定する |
| CWG 2299 | C++14 |
定数評価において
<cstdarg>
のマクロを使用できるかどうかが不明確であった |
va_arg
は禁止、
va_start
は未規定
|
| CWG 2400 | C++11 |
定数式で使用可能でないオブジェクトおよびその生存期間が呼び出しを含む
式の外側で開始されたオブジェクトに対するconstexpr仮想関数の呼び出し |
定数式ではない |
| CWG 2490 | C++20 |
定数評価における(擬似)デストラクタ呼び出しに
制限が欠如していた |
制限が追加された |
| CWG 2552 | C++23 |
コア定数式を評価する際、制御フローは非ブロック変数の宣言を
通過できなかった |
通過できるようになった |
| CWG 2558 | C++11 | 不定値は定数式になり得る | 定数式ではない |
| CWG 2647 | C++20 | volatile修飾型の変数は潜在的に定数となりうる | そうではない |
| CWG 2763 | C++11 |
[[
noreturn
]]
の違反は定数評価中に
検出される必要がなかった |
必須 |
| CWG 2851 | C++11 |
変換された定数式では
浮動小数点変換が許可されていなかった |
非縮小変換の浮動小数点変換を
許可する |
| CWG 2907 | C++11 |
コア定数式は
std::nullptr_t グル値に対して 左辺値から右辺値への変換を適用できなかった |
そのような変換を
適用可能 |
| CWG 2909 | C++20 |
初期化子を持たない変数は、そのデフォルト初期化が
何らかの初期化の実行をもたらす場合にのみ 定数初期化可能であった |
その型がconst-default-initializableである
場合にのみ定数初期化可能 |
| CWG 2924 |
C++11
C++23 |
[[noreturn]] (C++11) または [[assume]] (C++23) の制約に違反する式が
コア定数式であるかどうかは未規定であった |
実装定義である
|
| P2280R4 | C++11 |
この評価の外側で生存期間が開始されたオブジェクトまたは参照を参照する
識別子式または * this を含む式の評価は定数式ではない |
定数式である可能性がある |
関連項目
constexpr
指定子
(C++11)
|
変数または関数の値がコンパイル時に計算可能であることを指定する |
|
(C++11)
(C++17で非推奨)
(C++20で削除)
|
型がリテラル型かどうかをチェックする
(クラステンプレート) |
|
Cドキュメント
for
定数式
|
|