はじめに
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.x
やp1.y
もコンパイル時定数となり、配列のサイズ指定のような、コンパイル時定数が必要な場面で利用できます。
まとめ
今回は、C++11以降で導入された constexpr
の基本的な使い方を解説しました。
constexpr
は、変数や関数、オブジェクトをコンパイル時に評価できるようにする。- これにより、パフォーマンスの向上(実行時の計算をコンパイル時に移す)と、より強力なコンパイル時チェックが可能になる。
constexpr
は、テンプレートメタプログラミングなど、現代C++の高度な機能を支える重要な要素です。