Namespaces
Variants

constexpr specifier (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

目次

説明

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

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

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

constexpr variable

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

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

  • 定数破棄(constant destruction)を持つこと、つまり以下の条件のいずれかを満たす必要がある:
  • クラス型またはその(多次元配列を含む)配列ではないこと
  • クラス型であり、 constexpr デストラクタを持つか、その(多次元配列を含む)配列であり、かつオブジェクトを破棄する唯一の効果を持つ仮想的な式 e について、オブジェクトとその非変更可能な部分オブジェクト(変更可能な部分オブジェクトを除く)の生存期間が e 内で開始されるとみなされた場合に、 e コア定数式 となること

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

(C++20以降)

constexpr function

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

関数は、以下のすべての条件を満たす場合に constexpr-suitable となります:

  • これがコンストラクタ またはデストラクタ (C++20以降) である場合、そのクラスは virtual base class を持ちません。
  • これは virtual 関数ではありません。
(C++20まで)
  • その戻り値の型(存在する場合)は literal type です。
  • そのすべてのパラメータ型はliteral typeです。
(C++23まで)
(C++20以降)
  • その関数本体は = default = delete または以下のみを含む 複合文 である:
(C++14まで)
  • その関数本体は = default = delete または 以下のものを含まない (C++20まで) 複合文である:
(C++20まで)
  • 非リテラル型の変数の定義
  • 静的またはスレッド 記憶域期間 を持つ変数の定義
(C++14から)
(C++23まで)

インスタンス化された constexpr 関数を除いて、非テンプレートの constexpr 関数はconstexpr-suitableでなければなりません。

デフォルト化されず、テンプレート化されていない非コンストラクタ constexpr 関数について、その関数の呼び出しが コア定数式 の評価済み部分式となり得るような引数値が存在しない場合、プログラムは不適格であり、診断は不要である。

テンプレート化された constexpr 関数について、その関数/クラステンプレートの特殊化のいずれも、非テンプレート関数として見なした場合にconstexpr適合とならない場合、プログラムは不適格であり、診断は不要である。

(C++23まで)

与えられた文脈における constexpr 関数の呼び出しは、以下の例外を除く全ての点において、同じ文脈における同等の非 constexpr 関数の呼び出しと同じ結果を生成します:

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

constexpr constructor

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

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

constexpr コンストラクタがデフォルト化もテンプレート化もされていない場合、関数の呼び出しが何らかのオブジェクトの初期化完全式の評価済み部分式となり得るような引数値が存在しない場合、プログラムは不適格であり、診断は不要である。

(C++23まで)

constexpr デストラクタ

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

(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; // 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 関数内での動的ストレージ期間の操作

キーワード

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 で再宣言されると
インラインになる
変数はインラインに
ならない
  1. これは冗長です。なぜなら、 constexpr 指定子を持つ変数テンプレートの宣言が複数存在することはできないためです。

関連項目

定数式 コンパイル時に評価可能な を定義する
consteval 指定子 (C++20) 関数が 即時関数 であることを指定する。つまり、関数へのすべての呼び出しは定数評価で行われなければならない
constinit 指定子 (C++20) 変数が静的初期化( ゼロ初期化 および 定数初期化 )を持つことを表明する
Cドキュメント for constexpr