定数式
コンパイル時に評価できる式を定義します。
そのような式は、非型テンプレート引数、配列サイズ、および定数式を必要とするその他の文脈 (例) で使用できます。
int n = 1; std::array<int, n> a1; // Error: “n” is not a constant expression const int cn = 2; std::array<int, cn> a2; // OK: “cn” is a constant expression
目次 |
[編集] 定義
|
以下にリストされている定数式のカテゴリのいずれかに属する式は、定数式です。
|
(C++11まで) | ||
|
以下の式は、総称して定数式と呼ばれます
|
(C++11以降) (C++14まで) | ||
|
以下のエンティティは定数式として許容される結果です 定数式は、定数式として許容される結果であるエンティティを参照するglvalue コア定数式、または値が以下の制約を満たすprvalueコア定数式のいずれかです
|
(C++14以降) (C++26まで) | ||
|
定数式は、オブジェクトまたは非即時関数を参照するglvalue コア定数式、または値が以下の制約を満たすprvalueコア定数式のいずれかです
|
(C++26以降) |
式が定数式であるかどうかを判断する際、コピー省略は行われないと仮定されます。
C++98の定数式の定義は、完全に折りたたみボックス内にあります。以下の説明は、C++11以降のC++バージョンに適用されます。
[編集] リテラル型
以下の型は、総称してリテラル型と呼ばれます
- トリビアルなデストラクタ(C++20まで)constexpr デストラクタ(C++20から)を持つこと。
- そのすべての非静的非バリアントデータメンバおよび基底クラスが、非volatileなリテラル型であること。
- 以下の型のいずれかであること
| (C++17以降) |
リテラル型のオブジェクトのみが定数式内で作成できます。
[編集] コア定数式
コア定数式は、その評価が以下のいずれの言語構成要素も評価しない任意の式です
| 言語構成要素 | バージョン | 提案文書 |
|---|---|---|
this ポインタ。ただし、式の一部として評価されている constexpr 関数内、または暗黙的または明示的なクラスメンバアクセス式に現れる場合を除く |
N2235 | |
| 定数式で使用可能ではない静的またはスレッドストレージ期間を持つブロック変数の宣言を通過する制御フロー | (C++23から) | P2242R3 |
| このセクションは未完成です 理由: 以下の生HTML順序付きリストの内容を上記のwikitableに転送し、対応する項目を標準に導入した論文/CWG issueを追加します。ミニ例は保存されず、このページの下部で大きな例を形成するために組み合わせることができます。 |
- constexpr 宣言されていない関数 (またはコンストラクタ) を呼び出す関数呼び出し式
constexpr int n = std::numeric_limits<int>::max(); // OK: max() is constexpr constexpr int m = std::time(nullptr); // Error: std::time() is not constexpr
- 宣言されているが定義されていないconstexpr関数への関数呼び出し
- constexpr関数/コンストラクタの要件を満たさないconstexpr関数/コンストラクタテンプレートのインスタンス化への関数呼び出し
- 動的型がconstexpr-unknownであるオブジェクトに対して呼び出される、constexpr仮想関数への関数呼び出し
- 実装定義の制限を超える式
- 評価が何らかの形のコア言語の未定義または誤った(C++26から)動作につながる式。ただし、標準属性によって導入される可能性のある未定義動作を除く。
constexpr double d1 = 2.0 / 1.0; // OK constexpr double d2 = 2.0 / 0.0; // Error: not defined constexpr int n = std::numeric_limits<int>::max() + 1; // Error: overflow int x, y, z[30]; constexpr auto e1 = &y - &x; // Error: undefined constexpr auto e2 = &z[20] - &z[3]; // OK constexpr std::bitset<2> a; constexpr bool b = a[2]; // UB, but unspecified if detected
- (C++17まで) ラムダ式
- 左辺値から右辺値への暗黙の変換。ただし、以下に適用される場合を除く...
- 型(cv修飾される可能性のある) std::nullptr_t のglvalue
- 定数式で使用可能なオブジェクトを指す、非volatileなリテラル型のglvalue
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
- 共用体の非アクティブメンバまたはそのサブオブジェクトに適用される左辺値から右辺値への暗黙の変換または変更 (アクティブメンバと共通の初期シーケンスを共有している場合でも)
- 値が不定であるオブジェクトに対する左辺値から右辺値への暗黙の変換
- この式の評価外で生存期間が開始した、アクティブメンバが可変 (mutable) である (もしあれば) 共用体の暗黙のコピー/ムーブコンストラクタ/代入の呼び出し
- (C++20まで) 共用体のアクティブメンバを変更する代入式
- voidへのポインタからオブジェクトポインタ型
T*への変換。ただし、ポインタがヌルポインタ値を保持するか、型がTと類似しているオブジェクトを指す場合を除く(C++26から) -
dynamic_cast。そのオペランドが動的型がconstexpr-unknownであるオブジェクトを参照するglvalueである場合(C++20から) -
reinterpret_cast - (C++20まで) 疑似デストラクタ呼び出し
- (C++14まで) インクリメントまたはデクリメント演算子
-
(C++14から) オブジェクトの変更。ただし、オブジェクトが非volatileなリテラル型であり、その生存期間が式の評価内で開始した場合を除く
constexpr int incr(int& n) { return ++n; } constexpr int g(int k) { constexpr int x = incr(k); // Error: incr(k) is not a core constant // expression because lifetime of k // began outside the expression incr(k) return x; } constexpr int h(int k) { int x = incr(k); // OK: x is not required to be initialized // with a core constant expression return x; } constexpr int y = h(1); // OK: initializes y with the value 2 // h(1) is a core constant expression because // the lifetime of k begins inside the expression h(1)
- (C++20から) この式の評価内で生存期間が開始しなかったオブジェクトのデストラクタ呼び出しまたは疑似デストラクタ呼び出し
- 多相型のglvalueに適用される
typeid式であり、そのglvalueが動的型がconstexpr-unknownであるオブジェクトを参照する場合(C++20から) - new 式。ただし、以下の条件のいずれかが満たされる場合を除く:(C++20から)
- 選択された割り当て関数が置換可能なグローバル割り当て関数であり、割り当てられたストレージがこの式の評価内で解放される。
(C++20以降) - 選択された割り当て関数が、割り当てられた型
Tを持つ非割り当て形式であり、配置引数が以下のすべての条件を満たす
- 以下を指す
Tが配列型でない場合、型がTに類似するオブジェクト、またはTが配列型である場合、型がTに類似するオブジェクトの最初の要素。
- この式の評価内で期間が開始したストレージを指す。
(C++26以降) - delete 式。ただし、この式の評価内で割り当てられたストレージ領域を解放する場合を除く(C++20から)
- (C++20から) コルーチン: await-expression または yield-expression
- (C++20から) 結果が未指定の場合の三方比較
- 結果が未指定の等価演算子または関係演算子
- (C++14まで) 代入演算子または複合代入演算子
- (C++26まで) throw 式
- (C++26から) 例外オブジェクトの構築。ただし、その例外オブジェクトおよび std::current_exception または std::rethrow_exception の呼び出しによって作成されたすべての暗黙のコピーが、この式の評価内で破棄される場合を除く
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)); // OK since C++26 static_assert(always_throw()); // Error: uncaught exception
- asm-declaration
- va_arg マクロの呼び出し
goto文- 例外をスローする
dynamic_castまたはtypeid式または new 式(C++26から)。ただし、例外型の定義が到達可能でない場合(C++26から) - ラムダ式内で、this またはそのラムダの外で定義された変数への参照で、その参照がodr-useになる場合
void g() { const int n = 0; constexpr int j = *&n; // OK: outside of a lambda-expression [=] { constexpr int i = n; // OK: 'n' is not odr-used and not captured here. constexpr int j = *&n; // Ill-formed: '&n' would be an odr-use of 'n'. }; }
注意: ODR-useがクロージャへの関数呼び出しで行われる場合、それは this や囲む変数を参照しません。代わりにクロージャのデータメンバにアクセスするためです。
// OK: 'v' & 'm' are odr-used but do not occur in a constant-expression // within the nested lambda auto monad = [](auto v){ return [=]{ return v; }; }; auto bind = [](auto m){ return [=](auto fvm){ return fvm(m()); }; }; // OK to have captures to automatic objects created during constant expression evaluation. static_assert(bind(monad(2))(monad)() == monad(2)());
(C++17以降)
[編集] 追加要件
式 E が上記のいずれも評価しない場合でも、E を評価することが実行時未定義の動作になる場合、E がコア定数式であるかどうかは実装定義です。
式 E が上記のいずれも評価しない場合でも、E を評価することが以下のいずれかを評価する場合、E がコア定数式であるかどうかは未規定です
式がコア定数式であるかどうかを判断する目的で、Tがリテラル型である場合、std::allocator<T> のメンバ関数の本体の評価は無視されます。
式がコア定数式であるかどうかを判断する目的で、共用体のトリビアルなコピー/ムーブコンストラクタまたはコピー/ムーブ代入演算子の呼び出しの評価は、共用体のアクティブなメンバ (もしあれば) をコピー/ムーブすると見なされます。
|
式がコア定数式であるかどうかを判断する目的で、構造化束縛 bd を名指す識別子式の評価は、以下のセマンティクスを持ちます
|
(C++26以降) |
式をコア定数式として評価する間、式の評価外で生存期間が開始したオブジェクトまたは参照を参照するすべての識別子式および *this の使用は、そのオブジェクトまたは参照の特定のインスタンスを参照するものとして扱われ、その生存期間およびすべてのサブオブジェクト (すべての共用体メンバを含む) の生存期間は、定数評価全体を含みます。
- そのようなオブジェクトで定数式で使用可能ではない(C++20から)ものについては、オブジェクトの動的型はconstexpr-unknownです。
- そのような参照で定数式で使用可能ではない(C++20から)ものについては、参照は、参照される型の未指定のオブジェクトに束縛されているものとして扱われ、その生存期間およびすべてのサブオブジェクトの生存期間は定数評価全体を含み、その動的型はconstexpr-unknownです。
[編集] 整数定数式
整数定数式は、整数型または非スコープ列挙型の式で、暗黙的に純粋右辺値に変換され、変換された式がコア定数式であるものです。
整数定数式が期待される場所でクラス型の式が使用される場合、その式は整数型または非スコープ列挙型に文脈的に暗黙変換されます。
[編集] 変換定数式
型 T の変換定数式は、型 T に暗黙変換される式であり、変換された式は定数式であり、暗黙の変換シーケンスは以下のみを含みます
| (C++17以降) |
以下の文脈では変換定数式が必要です
| (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 は、点
明白な定数評価式以下の式 (宛先型への変換を含む) は明白な定数評価です
評価が明白な定数評価コンテキストで行われるかどうかは、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) | void* からの constexpr キャスト: constexpr 型消去に向けて |
202406L |
(C++26) | constexpr 配置 new と new[] | |
__cpp_constexpr_exceptions |
202411L |
(C++26) | constexpr 例外 |
[編集] 例
| このセクションは未完成です 理由: 例がありません |
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 94 | C++98 | 算術定数式は 変数や静的データメンバを含むことができなかった |
できるようになった |
| CWG 366 | C++98 | 文字列リテラルを含む式 は整数定数式になる可能性があった |
ならない |
| CWG 457 | C++98 | volatile変数を含む式 は整数定数式になる可能性があった |
ならない |
| CWG 1293 | C++11 | 文字列リテラルが 定数式で使用可能かどうかが不明確だった |
使用可能である |
| CWG 1311 | C++11 | volatile glvalueは定数式で使用できた | 禁止された |
| CWG 1312 | C++11 | reinterpret_castは定数式では禁止されているが、 void*との間のキャストで同じ効果が得られた |
禁止された変換 型 cv void* から オブジェクトポインタ型へ |
| CWG 1313 | C++11 | 未定義動作は許可されていた; すべてのポインタ減算は禁止されていた |
UB禁止;同一配列内 ポインタ減算はOK |
| CWG 1405 | C++11 | 定数式で使用可能なオブジェクトについて、 その可変サブオブジェクトも使用可能だった |
使用可能ではない |
| CWG 1454 | C++11 | constexpr関数を通じて参照で定数を渡すこと は許可されていなかった |
許可 |
| CWG 1455 | C++11 | 変換定数式はprvalueのみであった | lvalueも可能 |
| CWG 1456 | C++11 | アドレス定数式は 配列の終端の次のアドレスを指すことができなかった |
許可 |
| CWG 1535 | C++11 | オペランドが多相クラス型の typeid 式は、実行時チェックが関与しなくても コア定数式ではなかった |
オペランドの制約 は、多相クラス型の glvalueに限定される |
| 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 glvalueに 左辺値から右辺値への変換を適用できなかった |
そのような 変換を適用できる |
| 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言語のドキュメント
| |