constexpr
specifier
(since C++11)
-
-
constexpr- 変数 , 構造化バインディング (C++26以降) または関数の値が 定数式 内に現れることを指定する
-
目次 |
説明
constexpr 指定子は、エンティティの値をコンパイル時に評価可能であることを宣言します。そのようなエンティティは、コンパイル時 constant expressions のみが許可される場所で使用できます(適切な関数引数が与えられている場合)。
constexpr 指定子をオブジェクト宣言 または非静的メンバ関数 (C++14まで) で使用すると、 const を暗黙的に指定します。
A constexpr 指定子が関数の最初の宣言で使用される場合、 または static データメンバー (C++17以降) は inline を暗黙的に示します。関数または関数テンプレートのいずれかの宣言に constexpr 指定子がある場合、すべての宣言にその指定子を含める必要があります。
constexpr variable
変数 または変数テンプレート (C++14以降) は、以下の条件がすべて満たされる場合に constexpr として宣言できます:
|
(C++26まで) |
|
(C++26以降) |
|
constexpr 変数が 翻訳単位ローカル でない場合、定数式で使用可能な翻訳単位ローカルなエンティティを参照するように初期化してはならず、そのようなエンティティを参照する部分オブジェクトを持ってはならない。このような初期化は モジュールインターフェース単位 (存在する場合はその 非公開モジュールフラグメント を除く)またはモジュールパーティションでは許可されず、その他の文脈では非推奨である。 |
(C++20以降) |
constexpr function
関数または関数テンプレートは constexpr として宣言できます。
関数は、以下のすべての条件を満たす場合に constexpr-suitable となります:
|
(C++20まで) |
|
(C++23まで) |
|
(C++20以降) |
|
(C++14まで) | ||
|
(C++14から)
(C++23まで) |
インスタンス化された constexpr 関数を除いて、非テンプレートの constexpr 関数はconstexpr-suitableでなければなりません。
|
デフォルト化されず、テンプレート化されていない非コンストラクタ constexpr 関数について、その関数の呼び出しが コア定数式 の評価済み部分式となり得るような引数値が存在しない場合、プログラムは不適格であり、診断は不要である。 テンプレート化された constexpr 関数について、その関数/クラステンプレートの特殊化のいずれも、非テンプレート関数として見なした場合にconstexpr適合とならない場合、プログラムは不適格であり、診断は不要である。 |
(C++23まで) |
与えられた文脈における constexpr 関数の呼び出しは、以下の例外を除く全ての点において、同じ文脈における同等の非 constexpr 関数の呼び出しと同じ結果を生成します:
constexpr constructor
constexpr 関数の要件に加えて、コンストラクタがconstexprとして適切であるためには、以下のすべての条件を満たす必要があります:
|
(C++23まで) |
- このクラスには virtual base class がありません。
|
constexpr コンストラクタがデフォルト化もテンプレート化もされていない場合、関数の呼び出しが何らかのオブジェクトの初期化完全式の評価済み部分式となり得るような引数値が存在しない場合、プログラムは不適格であり、診断は不要である。 |
(C++23まで) |
constexpr デストラクタ
|
デストラクタは constexpr にできませんが、 trivial destructor は定数式内で暗黙的に呼び出すことができます。 |
(C++20まで) | ||
|
constexpr 関数の要件に加えて、デストラクタがconstexpr-suitableとなるためには以下のすべての条件を満たす必要があります:
|
(C++20以降) |
注記
|
constexpr int f(); constexpr bool b1 = noexcept(f()); // false, undefined constexpr function constexpr int f() { return 0; } constexpr bool b2 = noexcept(f()); // true, f() is a constant expression |
(C++17まで) |
|
コア定数式の要件を決して満たすことができないconstexpr関数を記述することが可能である: void f(int& i) // not a constexpr function { i = 0; } constexpr void g(int& i) // well-formed since C++23 { f(i); // unconditionally calls f, cannot be a constant expression } |
(C++23以降) |
リテラル型ではないクラスに対してもconstexprコンストラクタは許可されています。例えば、 std::shared_ptr のデフォルトコンストラクタはconstexprであり、 定数初期化 を可能にします。
constexprで参照変数を宣言できます(それらの初期化子は 参照定数式 である必要があります):
static constexpr int const& x = 42; // const intオブジェクトへのconstexpr参照 // (静的参照による寿命延長により、 // このオブジェクトは静的ストレージ期間を持つ)
|
constexpr関数内で try ブロックとインラインアセンブリが許可されているにもかかわらず、例外をスローすること (キャッチされない例外) (C++26以降) やアセンブリの実行は、定数式内では依然として許可されていません。 変数が定数破棄を持つ場合、そのデストラクタが非トリビアルであっても、デストラクタを呼び出すために機械語を生成する必要はありません。 非ラムダ、非特殊メンバー、非テンプレートのconstexpr関数は、暗黙的に即時関数になることはできません。ユーザーはそのような意図された関数定義を適格にするために、明示的に consteval を指定する必要があります。 |
(C++20以降) |
| 機能テストマクロ | 値 | 標準 | 機能 |
|---|---|---|---|
__cpp_constexpr
|
200704L
|
(C++11) | constexpr |
201304L
|
(C++14) | 緩和された constexpr 、 非 const constexpr メソッド | |
201603L
|
(C++17) | Constexpr ラムダ | |
201907L
|
(C++20) | constexpr 関数内での自明な デフォルト初期化 と asm宣言 | |
202002L
|
(C++20) | 定数評価における共用体のアクティブメンバーの変更 | |
202110L
|
(C++23) | constexpr関数内での非 リテラル型 変数、ラベル、および goto 文 | |
202207L
|
(C++23) | 一部の constexpr 制限の緩和 | |
202211L
|
(C++23) | constexpr 関数内での static constexpr 変数の許可 | |
202306L
|
(C++26) | void * からのConstexprキャスト:constexpr型消去に向けて | |
__cpp_constexpr_in_decltype
|
201711L
|
(C++11)
(DR) |
定数評価に 必要な場合の関数と変数定義の生成 |
__cpp_constexpr_dynamic_alloc
|
201907L
|
(C++20) | constexpr 関数内での動的ストレージ期間の操作 |
キーワード
例
C++11/14の constexpr 関数を定義し、階乗を計算します。文字列リテラルを拡張するリテラル型を定義します:
#include <iostream> #include <stdexcept> // C++11 constexpr関数は反復ではなく再帰を使用する constexpr int factorial(int n) { return n <= 1 ? 1 : (n * factorial(n - 1)); } // C++14 constexpr関数はローカル変数とループを使用できる #if __cplusplus >= 201402L constexpr int factorial_cxx14(int n) { int res = 1; while (n > 1) res *= n--; return res; } #endif // C++14 // リテラルクラス class conststr { const char* p; std::size_t sz; public: template<std::size_t N> constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {} // constexpr関数は例外をスローすることでエラーを通知する // C++11では、条件演算子 ?: から行う必要がある constexpr char operator[](std::size_t n) const { return n < sz ? p[n] : throw std::out_of_range(""); } constexpr std::size_t size() const { return sz; } }; // C++11 constexpr関数はすべてを単一のreturn文にまとめる必要があった // (C++14ではその要件はない) constexpr std::size_t countlower(conststr s, std::size_t n = 0, std::size_t c = 0) { return n == s.size() ? c : 'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) : countlower(s, n + 1, c); } // テスト用のコンパイル時定数を必要とする出力関数 template<int n> struct constN { constN() { std::cout << n << '\n'; } }; int main() { std::cout << "4! = "; constN<factorial(4)> out1; // コンパイル時に計算 volatile int k = 8; // volatileを使用して最適化を無効化 std::cout << k << "! = " << factorial(k) << '\n'; // 実行時に計算 std::cout << "「Hello, world!」内の小文字の数は "; constN<countlower("Hello, world!")> out2; // 暗黙的にconststrに変換 constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; constexpr int length_a = sizeof a / sizeof(int); // C++17ではstd::size(a)、 // C++20ではstd::ssize(a) std::cout << "長さ " << length_a << " の配列の要素: "; for (int i = 0; i < length_a; ++i) std::cout << a[i] << ' '; std::cout << '\n'; }
出力:
4! = 24 8! = 40320 「Hello, world!」の小文字の数は9です 長さ12の配列の要素: 0 1 2 3 4 5 6 7 8 0 0 0
不具合報告
以下の動作変更欠陥報告書は、以前に公開されたC++標準に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| CWG 1358 | C++11 |
テンプレート化された
constexpr
関数も少なくとも1つの有効な
引数値を持つ必要があった |
不要 |
| CWG 1359 | C++11 |
constexpr
共用体コンストラクタはすべての
データメンバを初期化する必要があった |
空でない共用体では正確に1つの
データメンバを初期化する |
| CWG 1366 | C++11 |
関数本体が
=
default
または
=
delete
である
constexpr コンストラクタを持つクラスは仮想基底クラスを持てた |
そのようなクラスは仮想基底クラスを
持つことができない |
| CWG 1595 | C++11 |
constexpr
委譲コンストラクタは関連するすべての
コンストラクタが constexpr であることを要求した |
対象コンストラクタのみが
constexpr であることを要求する |
| CWG 1712 | C++14 |
constexpr
変数テンプレートはすべての宣言に
constexpr 指定子を含む必要があった [1] |
不要になった |
| CWG 1911 | C++11 | 非リテラル型に対する constexpr コンストラクタは許可されなかった | 定数初期化で許可される |
| CWG 2004 | C++11 |
mutableメンバを持つ共用体のコピー/ムーブは
定数式で許可されていた |
mutableバリアントは暗黙的な
コピー/ムーブを不適格にする |
| CWG 2022 | C++98 |
同等の
constexpr
関数と非
constexpr
関数が
同等の結果を生成するかどうかは、コピー省略が 実行されるかどうかに依存する可能性があった |
定数式では常にコピー省略が
実行されると仮定する |
| CWG 2163 | C++14 |
constexpr
関数内でラベルが許可されていた
( goto 文は禁止されているにもかかわらず) |
ラベルも禁止される |
| CWG 2268 | C++11 |
mutableメンバを持つ共用体のコピー/ムーブは
CWG issue 2004 の解決により禁止されていた |
オブジェクトが定数式内で作成される
場合は許可される |
| CWG 2278 | C++98 | CWG issue 2022 の解決は実装不可能だった |
定数式ではコピー省略が決して
実行されないと仮定する |
| CWG 2531 | C++11 |
非インライン変数は
constexpr
で再宣言されると
インラインになる |
変数はインラインに
ならない |
- ↑ これは冗長です。なぜなら、 constexpr 指定子を持つ変数テンプレートの宣言が複数存在することはできないためです。
関連項目
| 定数式 | コンパイル時に評価可能な 式 を定義する |
consteval
指定子
(C++20)
|
関数が 即時関数 であることを指定する。つまり、関数へのすべての呼び出しは定数評価で行われなければならない |
constinit
指定子
(C++20)
|
変数が静的初期化( ゼロ初期化 および 定数初期化 )を持つことを表明する |
|
Cドキュメント
for
constexpr
|
|