【C++】constexprとは?コンパイル時定数を使いこなす方法

目次

はじめに

C++で、配列のサイズやテンプレートの引数を指定する際、その値はコンパイル時に確定している必要があります。従来は、const修飾子を付けた定数などがこの役割を担っていましたが、より複雑な計算結果をコンパイル時定数として扱いたい、という要求に応えるのが constexpr (constant expression) です。

constexpr を使うと、

  • constexpr変数: 値がコンパイル時に確定する定数。
  • constexpr関数: 引数がコンパイル時定数であれば、その戻り値もコンパイル時に計算できる関数。
  • constexprコンストラクタ: コンパイル時にオブジェクトを生成できるコンストラクタ。

といったものを定義できます。これにより、従来は実行時にしか行えなかった計算を、コンパイル時に肩代わりさせ、プログラムの実行速度を向上させることができます。


1. constexpr 変数

constexpr を付けて宣言された変数は、その値がコンパイル時に完全に決定されるコンパイル時定数となります。

constexpr int MAX_SIZE = 100;
int data_array[MAX_SIZE]; // OK: 配列のサイズとして使える

constexpr double PI = 3.14; // OK

const と似ていますが、const は必ずしもコンパイル時定数であるとは限らないのに対し、constexpr は常にコンパイル時定数であることを保証します。


2. constexpr 関数

constexpr を付けて定義された関数は、引数が全てコンパイル時定数であれば、その関数の呼び出し結果もコンパイル時定数として評価されます。

サンプルコード

#include <iostream>
#include <array>

// 階乗を計算するconstexpr関数
constexpr long long factorial(int n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

int main() {
    // 1. コンパイル時に評価される
    // factorial(5)の結果(120)が、コンパイル時に計算される
    constexpr long long result_at_compile_time = factorial(5);
    std::cout << "5! = " << result_at_compile_time << std::endl;

    // 配列のサイズ指定にも使える
    std::array<int, factorial(4)> my_array; // サイズ24の配列
    std::cout << "配列のサイズ: " << my_array.size() << std::endl;

    // 2. 実行時に評価される
    int num = 6;
    // 引数が変数なので、通常の関数として実行時に呼び出される
    long long result_at_run_time = factorial(num);
    std::cout << "6! = " << result_at_run_time << std::endl;
    
    return 0;
}

解説: constexpr関数は、引数によってコンパイル時にも実行時にも動作できる、二面性を持った関数です。


3. constexpr コンストラクタ

クラスのコンストラクタにconstexprを付けると、特定の条件下で、そのクラスのオブジェクトをコンパイル時に生成できます。

サンプルコード

#include <iostream>

class Point {
public:
    int x, y;
    
    // constexprコンストラクタ
    constexpr Point(int ix, int iy) : x(ix), y(iy) {}
};

int main() {
    // constexprオブジェクトを、constexprコンストラクタで生成
    constexpr Point p1(10, 20);
    
    // constexprオブジェクトのメンバは、コンパイル時定数として扱える
    int arr[p1.x + p1.y]; // サイズ30の配列
    
    std::cout << "配列のサイズ: " << std::size(arr) << std::endl;

    return 0;
}

解説: p1はコンパイル時に生成されるため、そのメンバp1.xp1.yもコンパイル時定数となり、配列のサイズ指定のような、コンパイル時定数が必要な場面で利用できます。


まとめ

今回は、C++11以降で導入された constexpr の基本的な使い方を解説しました。

  • constexpr は、変数や関数、オブジェクトをコンパイル時に評価できるようにする。
  • これにより、パフォーマンスの向上(実行時の計算をコンパイル時に移す)と、より強力なコンパイル時チェックが可能になる。

constexpr は、テンプレートメタプログラミングなど、現代C++の高度な機能を支える重要な要素です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次