Menu
Coddy logo textTech

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 を使用でき、オブジェクト全体をコンパイル時に作成できます。これは、ルックアップテーブル、構成値、またはプログラムの実行中に変更されないあらゆるデータに特に便利です。

challenge icon

チャレンジ

簡単

コードを3つのファイルに分けて整理します:

  • MathUtils.h:コンパイル時に評価される数学の関数をDefineします。

    次のfunctionsをCreateします:

    • cubeintを受け取り、その立方(n * n * n)を返すconstexpr function
    • triangularNumber:公式 n * (n + 1) / 2 を使ってn番目の三角数を計算するconstexpr function。この課題では、結果をconstexpr変数に格納し、compile-time contextでのみ呼び出します。
    • sumOfSquares:2つのintegersを受け取り、それらの平方の和(a*a + b*b)を返すconstexpr function
  • Config.h:コンパイル時定数を使用して設定構造体をCreateします。

    Config structを、3つのintegers(widthheightdepth)を受け取るconstexpr constructor付きでDefineします。これらをpublic membersとして保存します。また、width * height * depthを返す、volume()という名前のconstexpr methodも追加します。

    structの下で、値10、20、5でinitializedされたDEFAULT_CONFIGというconstexpr global constantをCreateします。

  • main.cpp:runtime valuesを表す2つのintegersをinputから読み取ります。

    まず、constexpr variablesを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を使用して、constexpr functionsがruntimeでも動作できることをDemonstrateします:

    • 最初のinputを使ってcube()をCallし、次をprintします:Cube of [input]: [result]
    • both inputsを使ってsumOfSquares()をCallし、次をprintします:Sum of squares: [result]

例えば、inputsが34の場合:

Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 3: 27
Sum of squares: 25

inputsが512の場合:

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;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C++オンラインコンパイラ