constexprとconsteval
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 87/104。
C++では、実行時ではなくコンパイル時に計算を行うことが可能であり、これによりパフォーマンスを大幅に向上させることができます。constexprキーワード(C++11)およびconstevalキーワード(C++20)により、式がいつ評価されるかを制御できるようになります。
constexpr 関数は、定数の引数が与えられた場合にはコンパイル時に評価されることができますが、定数ではない入力を用いて実行時に実行することも可能です:
#include <iostream>
constexpr int square(int n) {
return n * n;
}
int main() {
constexpr int compileTime = square(5); // コンパイル時に評価される
int x = 7;
int runtime = square(x); // 実行時に評価される
std::cout << compileTime << "\n"; // 25
std::cout << runtime << "\n"; // 49
}コンパイル時評価を保証する必要がある場合は、consteval を使用します。consteval 関数は定数を生成しなければなりません。実行時の値を使用して呼び出すと、コンパイルエラーになります。
consteval int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
int main() {
constexpr int result = factorial(5); // OK: 120 はコンパイル時に計算されます
// int x = 5;
// int bad = factorial(x); // エラー: x は定数ではありません
}constexpr は変数やクラスのコンストラクタにも使用でき、オブジェクト全体をコンパイル時に生成することが可能になります。これは、ルックアップテーブルや設定値、あるいはプログラムの実行中に変更されないあらゆるデータに対して特に有用です。
チャレンジ
簡単コードを3つのファイルに分けて構成します:
MathUtils.h: コンパイル時数学関数を定義します。以下の関数を作成してください:
cube—intを受け取り、その立方体 (n * n * n) を返すconstexpr関数triangularNumber— 公式 n * (n + 1) / 2 を使用して n 番目の三角数を計算するconstexpr関数。これは常にコンパイル時に評価される必要があります。sumOfSquares— 2つの整数を受け取り、それらの二乗の和 (a*a + b*b) を返すconstexpr関数
Config.h: コンパイル時定数を使用して設定構造体を作成します。3つの整数
width、height、depthを受け取るconstexprコンストラクタを持つConfig構造体を定義します。これらを公開メンバとして保存してください。また、width * height * depth を返すvolume()というconstexprメソッドを追加します。構造体の下に、値 10、20、5 で初期化された
DEFAULT_CONFIGという名前のconstexprグローバル定数を作成します。main.cpp: 実行時の値を表す2つの整数を入力から読み取ります。まず、
constexpr変数を作成することでコンパイル時評価を実演します:cube(4)を constexpr 変数に格納し、次のように出力します:Cube of 4: [value]triangularNumber(10)を constexpr 変数に格納し、次のように出力します:10th triangular number: [value]- デフォルト設定のボリュームを出力します:
Default volume: [value]
次に、2つの入力値を使用して、
constexpr関数が実行時にも機能することを実演します:- 最初の入力で
cube()を呼び出し、次のように出力します:Cube of [input]: [result] - 両方の入力で
sumOfSquares()を呼び出し、次のように出力します:Sum of squares: [result]
例えば、入力が 3 と 4 の場合:
Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 3: 27
Sum of squares: 25入力が 5 と 12 の場合:
Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 5: 125
Sum of squares: 169チートシート
C++では、constexpr (C++11) および consteval (C++20) キーワードを使用して、コンパイル時に計算を行うことができます。
constexpr 関数は、定数の引数を使用するとコンパイル時に評価されることが可能ですが、定数ではない入力を使用すると実行時にも動作します。
constexpr int square(int n) {
return n * n;
}
constexpr int compileTime = square(5); // コンパイル時に評価される
int x = 7;
int runtime = square(x); // 実行時に評価されるconsteval 関数は、必ずコンパイル時に評価されなければなりません。実行時の値を使用して呼び出すと、コンパイルエラーが発生します。
consteval int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
constexpr int result = factorial(5); // OK: コンパイル時に計算される
// int x = 5;
// int bad = factorial(x); // エラー: x は定数ではありませんconstexpr は、変数、クラスのコンストラクタ、およびメソッドに使用して、コンパイル時のオブジェクト生成を可能にすることができます。
struct Config {
int width, height, depth;
constexpr Config(int w, int h, int d)
: width(w), height(h), depth(d) {}
constexpr int volume() const {
return width * height * depth;
}
};
constexpr Config config(10, 20, 5); // コンパイル時に生成される自分で試してみよう
#include <iostream>
#include "MathUtils.h"
#include "Config.h"
using namespace std;
int main() {
// 入力から2つの整数を読み取る
int input1, input2;
cin >> input1;
cin >> input2;
// TODO: コンパイル時評価を実演する
// cube(4)を格納するconstexpr変数を作成し、"Cube of 4: [value]"と出力する
// TODO: triangularNumber(10)を格納するconstexpr変数を作成する
// そして、"10th triangular number: [value]"と出力する
// TODO: デフォルト設定のボリュームを出力する: "Default volume: [value]"
// TODO: constexpr関数の実行時における使用を実演する
// input1を引数にしてcube()を呼び出し、"Cube of [input1]: [result]"と出力する
// TODO: 両方の入力を引数にしてsumOfSquares()を呼び出す
// そして、"Sum of squares: [result]"と出力する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス12モダンC++の機能
ムーブセマンティクスと右辺値完全転送ラムダ式の詳細std::functionとstd::bindconstexprとconsteval構造化束縛optional, variant, any