constexprとconsteval
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 87/104。
C++では、ランタイムではなくcompile 時に計算を実行できるため、パフォーマンスを大幅に向上させられます。constexprキーワード(C++11)とconstevalキーワード(C++20)を使うことで、式がいつ評価されるかを制御できます。
constexpr function は、定数引数が与えられた場合にはコンパイル時に評価できますが、非定数の入力を使用して実行時に動作することもできます。
#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); // ERROR: x は定数ではありません
}変数やクラスのコンストラクターでも constexpr を使用でき、オブジェクト全体をコンパイル時に作成できます。これは、ルックアップテーブル、構成値、またはプログラムの実行中に変更されないあらゆるデータに特に便利です。
チャレンジ
簡単コードを3つのファイルに分けて整理します:
MathUtils.h:コンパイル時に評価される数学の関数をDefineします。次のfunctionsをCreateします:
cube:intを受け取り、その立方(n * n * n)を返すconstexprfunctiontriangularNumber:公式 n * (n + 1) / 2 を使ってn番目の三角数を計算するconstexprfunction。この課題では、結果をconstexpr変数に格納し、compile-time contextでのみ呼び出します。sumOfSquares:2つのintegersを受け取り、それらの平方の和(a*a + b*b)を返すconstexprfunction
Config.h:コンパイル時定数を使用して設定構造体をCreateします。Configstructを、3つのintegers(width、height、depth)を受け取るconstexprconstructor付きでDefineします。これらをpublic membersとして保存します。また、width * height * depthを返す、volume()という名前のconstexprmethodも追加します。structの下で、値10、20、5でinitializedされた
DEFAULT_CONFIGというconstexprglobal constantをCreateします。main.cpp:runtime valuesを表す2つのintegersをinputから読み取ります。まず、
constexprvariablesをCreateしてcompile-time evaluationをDemonstrateします:cube(4)をconstexpr変数に格納し、次をprintします:Cube of 4: [value]triangularNumber(10)をconstexpr変数に格納し、次をprintします:10th triangular number: [value]- Default configのvolumeをprintします:
Default volume: [value]
次に、2つのinput valuesを使用して、
constexprfunctionsがruntimeでも動作できることをDemonstrateします:- 最初のinputを使って
cube()をCallし、次をprintします:Cube of [input]: [result] - both inputsを使って
sumOfSquares()をCallし、次をprintします:Sum of squares: [result]
例えば、inputsが3と4の場合:
Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 3: 27
Sum of squares: 25inputsが5と12の場合:
Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 5: 125
Sum of squares: 169自分で試してみよう
#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: Create a constexpr variable storing triangularNumber(10)
// and print: "10th triangular number: [value]"
// TODO: Print the default config's volume: "Default volume: [value]"
// TODO: constexpr関数の実行時使用を実証する
// input1でcube()を呼び出し、次を出力する: "Cube of [input1]: [result]"
// TODO: Call sumOfSquares() with both inputs
// and print: "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自分で練習してみよう: C++オンラインコンパイラ