← SEARCHABLE ARCHIVE
C / C++ · 2026-08-11

C++ 基礎からマスターまで — 第17回

constexpr と consteval でコンパイル時に計算する

INTERACTIVE READING MODE →

本ブログの記事は、講義を目的として作成しています。 内容に誤りが含まれる可能性があるため、対象コンパイラと標準ライブラリの資料も確認してください。

C++ は一部の計算をプログラム開始前に実行できます。constexpr、consteval、constinit は、それぞれ定数評価、必須のコンパイル時呼び出し、静的初期化を表す別の契約です。

constexpr は二つの状況で動く

constexpr int Square(int value)
{
    return value * value;
}

constexpr int tableSize = Square(8); // コンパイル時
int input = ReadInput();
int result = Square(input);          // 実行時

constexpr 関数は定数評価が可能ですが、すべての呼び出しがコンパイル時に行われるわけではありません。引数が定数で、結果が constant expression を必要とする位置で使われる場合は、コンパイラが評価します。

consteval はコンパイル時呼び出しを強制する

consteval unsigned int HashLiteral(std::string_view text)
{
    unsigned int hash = 2166136261u;
    for (char ch : text)
        hash = (hash ^ static_cast<unsigned char>(ch)) * 16777619u;
    return hash;
}

constexpr auto playerId = HashLiteral("Player");

consteval 関数の呼び出しは必ず constant expression でなければなりません。ビルド時に固定すべきアセットキーやプロトコルタグに向いています。

ハッシュには衝突があります。コンパイル時に計算しても一意性は保証されないため、衝突方針と元のキーの検証が必要です。

if constexpr で無効な分岐を除外する

template <typename T>
void Serialize(const T& value, Writer& writer)
{
    if constexpr (std::integral<T>)
        writer.WriteInteger(value);
    else
        value.Serialize(writer);
}

通常の if と異なり、選ばれなかった if constexpr の分岐はそのテンプレート実体から破棄されます。選ばれない側の操作が対象型に存在しなくても構いません。

constinit は静的初期化を検査する

constinit int globalLimit = 64;

constinit は static storage duration のオブジェクトが静的初期化されることを確認します。値を変更不能にするものではなく、それは const の役目です。

コンパイル時処理は実行時初期化を減らし、誤りを早く見つけられますが、ビルド時間や診断、binary サイズを増やすことがあります。固定規則の早期検証に価値がある場面で使います。