名前空間
変種
操作

constexpr 指定子 (C++11 以降)

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 
  • constexpr - 変数構造化束縛(C++26 以降)、または関数の値が定数式に現れることができることを指定する。

目次

[編集] 解説

constexpr 指定子は、エンティティの値をコンパイル時に評価できることを宣言します。そのようなエンティティは、コンパイル時定数式のみが許可される場所で使用できます(適切な関数引数が与えられれば)。

オブジェクト宣言または非静的メンバ関数(C++14 まで)で使用されるconstexpr指定子は、constを意味します。

関数または静的データメンバ(C++17 以降)の最初の宣言で使用されるconstexpr指定子は、inlineを意味します。関数または関数テンプレートのいずれかの宣言にconstexpr指定子がある場合、すべての宣言にその指定子が含まれている必要があります。

[編集] constexpr 変数

変数または変数テンプレート(C++14 以降)は、以下のすべての条件が満たされている場合にconstexprと宣言できます。

  • その宣言は定義であること。
  • リテラル型であること。
  • 初期化されていること (宣言によって)。
(C++26まで)
(C++26以降)

  • 定数破棄を持つこと。これは以下の条件のいずれかを満たすことを意味します。
  • クラス型ではなく、その (多次元の可能性のある) 配列でもないこと。
  • constexprデストラクタを持つクラス型、またはその (多次元の可能性のある) 配列であり、かつ、オブジェクトを破棄することのみを唯一の副作用とする仮定的な式eに対して、そのオブジェクトとその非変更可能なサブオブジェクト (ただし、その変更可能なサブオブジェクトは含まない) の寿命がe内で開始するとみなされる場合、eコア定数式であること。

constexpr変数が翻訳単位ローカルでない場合、定数式で使用可能な翻訳単位ローカルエンティティを参照するように初期化してはならず、またそのようなエンティティを参照するサブオブジェクトを持ってはなりません。そのような初期化は、モジュールインターフェース単位 (そのプライベートモジュールフラグメントが存在する場合、その外側) またはモジュールパーティションでは許可されず、他のコンテキストでは非推奨です。

(C++20以降)

[編集] constexpr 関数

関数または関数テンプレートはconstexprと宣言できます。

関数がconstexpr-suitableであるのは、以下のすべての条件が満たされている場合です。

  • コンストラクタまたはデストラクタ(C++20 以降)である場合、そのクラスは仮想基底クラスを持たないこと。
  • 仮想関数ではないこと。
(C++20まで)
  • その戻り値の型(存在する場合)はリテラル型であること。
  • そのパラメータの型がそれぞれリテラル型であること。
(C++23まで)
(C++20以降)
  • その関数本体が= default= delete、または以下のもののみを囲む複合文であること。
(C++14まで)
  • その関数本体は= default= delete、または複合文であり(C++20 まで)、以下のものを含まないこと。
(C++20まで)
  • 非リテラル型の変数の定義
  • 静的またはスレッド記憶域期間を持つ変数の定義
(C++14以降)
(C++23まで)

インスタンス化されたconstexpr関数を除き、非テンプレートconstexpr関数はconstexpr-suitableである必要があります。

デフォルト化もテンプレート化もされていない非コンストラクタconstexpr関数について、関数の呼び出しがコア定数式の評価された副式となるような引数値が存在しない場合、プログラムは ill-formed であり、診断は不要です。

テンプレート化されたconstexpr関数について、関数/クラステンプレートの特殊化が、非テンプレート関数として考慮した場合にconstexpr-suitableとならない場合、プログラムはill-formedであり、診断は不要です。

(C++23まで)

特定のコンテキストでのconstexpr関数の呼び出しは、同じコンテキストでの同等の非constexpr関数の呼び出しと、以下の例外を除いて、すべての点で同じ結果を生成します。

  • constexpr関数の呼び出しは、定数式に現れることがあります。
  • コピー省略は定数式では実行されません。

[編集] constexpr コンストラクタ

constexpr関数の要件に加えて、コンストラクタはconstexpr-suitableであるために以下のすべての条件を満たす必要があります。

  • その関数本体は= deleteであるか、以下の追加要件を満たすこと。
  • クラスがバリアントメンバを持つ共用体である場合、そのうちの1つだけが初期化されること。
  • クラスが共用体のようなクラスであるが共用体ではない場合、バリアントメンバを持つ各匿名共用体メンバについて、そのうちの1つだけが初期化されること。
  • すべての非バリアント非静的データメンバおよび基底クラスサブオブジェクトが初期化されていること。
(C++20まで)
  • コンストラクタが委譲コンストラクタである場合、ターゲットコンストラクタはconstexprコンストラクタであること。
  • コンストラクタが非委譲コンストラクタである場合、非静的データメンバおよび基底クラスサブオブジェクトを初期化するために選択されたすべてのコンストラクタはconstexprコンストラクタであること。
(C++23まで)

デフォルト化もテンプレート化もされていないconstexprコンストラクタについて、関数呼び出しが定数式の対象となるオブジェクトの初期化完全式の評価された副式となるような引数値が存在しない場合、プログラムは ill-formed であり、診断は不要です。

(C++23まで)

[編集] constexpr デストラクタ

デストラクタはconstexprにはなりませんが、自明なデストラクタは定数式で暗黙的に呼び出すことができます。

(C++20まで)

constexpr関数の要件に加えて、デストラクタはconstexpr-suitableであるために以下のすべての条件を満たす必要があります。

  • クラス型またはその(多次元の可能性のある)配列であるすべてのサブオブジェクトに対して、そのクラス型はconstexprデストラクタを持つこと。
(C++23まで)
  • そのクラスは仮想基底クラスを持たないこと。
(C++20以降)

[編集] 備考

noexcept演算子は定数式に対して常にtrueを返すため、特定のconstexpr関数の呼び出しが定数式のブランチを実行するかどうかをチェックするために使用できます。

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; // constexpr reference to a const int object
                                    // (the object has static storage duration
                                    //  due to life extension by a static reference)

tryブロックとインラインアセンブリがconstexpr関数で許可されていても、キャッチされない(C++26 以降)例外をスローしたり、アセンブリを実行したりすることは、定数式では依然として禁止されています。

変数が定数破棄を持つ場合、そのデストラクタが自明でなくても、デストラクタを呼び出すためのマシンコードを生成する必要はありません。

非ラムダ、非特殊メンバ、非テンプレートconstexpr関数は、暗黙的に即時関数になることはできません。そのような意図された関数定義を整形式にするには、ユーザーが明示的に`consteval`とマークする必要があります。

(C++20以降)
機能テストマクロ 規格 機能
__cpp_constexpr 200704L (C++11) constexpr
201304L (C++14) 緩和されたconstexprconst 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 関数における動的ストレージ期間の操作

[編集] キーワード

constexpr

[編集]

階乗を計算するC++11/14のconstexpr関数を定義し、文字列リテラルを拡張するリテラル型を定義します。

#include <iostream>
#include <stdexcept>
 
// C++11 constexpr functions use recursion rather than iteration
constexpr int factorial(int n)
{
    return n <= 1 ? 1 : (n * factorial(n - 1));
}
 
// C++14 constexpr functions may use local variables and loops
#if __cplusplus >= 201402L
constexpr int factorial_cxx14(int n)
{
    int res = 1;
    while (n > 1)
        res *= n--;
    return res;
}
#endif // C++14
 
// A literal class
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 functions signal errors by throwing exceptions
    // in C++11, they must do so from the conditional operator ?:
    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 functions had to put everything in a single return statement
// (C++14 does not have that requirement)
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);
}
 
// An output function that requires a compile-time constant, for testing
template<int n>
struct constN
{
    constN() { std::cout << n << '\n'; }
};
 
int main()
{
    std::cout << "4! = ";
    constN<factorial(4)> out1; // computed at compile time
 
    volatile int k = 8; // disallow optimization using volatile
    std::cout << k << "! = " << factorial(k) << '\n'; // computed at run time
 
    std::cout << "The number of lowercase letters in \"Hello, world!\" is ";
    constN<countlower("Hello, world!")> out2; // implicitly converted to conststr
 
    constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
    constexpr int length_a = sizeof a / sizeof(int); // std::size(a) in C++17,
                                                      // std::ssize(a) in C++20
    std::cout << "Array of length " << length_a << " has elements: ";
    for (int i = 0; i < length_a; ++i)
        std::cout << a[i] << ' ';
    std::cout << '\n';
}

出力

4! = 24
8! = 40320
The number of lowercase letters in "Hello, world!" is 9
Array of length 12 has elements: 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 constexprコンストラクタを持つクラスの関数本体
= defaultまたは= deleteである場合、仮想基底クラスを持つことができた
そのようなクラスはどちらもできない
仮想基底クラスを持つ
CWG 1595 C++11 constexpr委譲コンストラクタが必要とされた
すべての関連するコンストラクタがconstexprであること
ターゲットのみが必要とされる
コンストラクタはconstexprであること
CWG 1712 C++14 constexpr変数テンプレートは
そのすべての宣言にconstexpr指定子が含まれていること[1]
もう必要ない
CWG 1911 C++11 非リテラル型のconstexprコンストラクタは許可されなかった 定数初期化で許可されるようになった
CWG 2004 C++11 可変メンバを持つ共用体のコピー/ムーブ
定数式で許可された
可変バリアントは対象外となる
暗黙的なコピー/ムーブ
CWG 2022 C++98 同等のconstexprと非constexpr関数が
同じ結果を生成するかどうかは
コピー省略が実行されるかどうかに依存する
定数式では常にコピー省略が
実行されると仮定する
CWG 2163 C++14 ラベルはconstexpr関数で許可されていた
goto文が禁止されているにもかかわらず
ラベルも禁止
CWG 2268 C++11 可変メンバーを持つ共用体のコピー/ムーブは
CWG issue 2004の解決によって禁止された
オブジェクトが作成された場合に許可される
定数式内で
CWG 2278 C++98 CWG issue 2022の解決は実装不可能だった コピー省略は決して行われないと仮定する
実行されると仮定する
CWG 2531 C++11 非インライン変数がインラインになった
constexprで再宣言された場合
変数はインラインにならない
インラインにならない
  1. constexpr指定子を持つ変数テンプレートの宣言は複数存在しないため、これは冗長です。

[編集] 関連項目

ない コンパイル時に評価可能なを定義する
consteval 指定子(C++20) 関数が即時関数であることを指定する。つまり、関数へのすべての呼び出しは定数評価内で行われなければならない。[編集]
constinit 指定子(C++20) 変数が静的初期化、すなわちゼロ初期化定数初期化を持つことを表明する。[編集]
English 日本語 中文(简体) 中文(繁體)