7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

C++のconstexprはコンパイル時計算を可能にする強力な機能。

「実行時に計算するんじゃなくて、コンパイル時に全部終わらせる」という発想、かなりロマンがある。

C++11からC++20までの進化を追いながら、constexprの全機能を解説するよ。

1. 基本的なconstexpr関数

constexpr int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

constexpr int fibonacci(int n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// コンパイル時に計算される
constexpr int fact5 = factorial(5);   // 120
constexpr int fib10 = fibonacci(10);  // 55

// static_assert で検証
static_assert(factorial(5) == 120, "factorial test");

2. constexpr変数

constexpr double PI = 3.14159265358979323846;
constexpr double E = 2.71828182845904523536;
constexpr int MAX_SIZE = 1024;

// constexprはconstより厳密
// const int x = get_runtime_value();  // OK
// constexpr int y = get_runtime_value();  // エラー!

3. constexprクラス

class Point {
public:
    int x, y;
    
    constexpr Point(int x = 0, int y = 0) : x(x), y(y) {}
    
    constexpr Point operator+(const Point& other) const {
        return Point(x + other.x, y + other.y);
    }
    
    constexpr int dot(const Point& other) const {
        return x * other.x + y * other.y;
    }
    
    constexpr int manhattanDistance() const {
        return (x >= 0 ? x : -x) + (y >= 0 ? y : -y);
    }
};

constexpr Point p1(3, 4);
constexpr Point p2(1, 2);
constexpr Point p3 = p1 + p2;  // (4, 6)
constexpr int dot = p1.dot(p2);  // 11

4. constexpr配列操作

constexpr int sum_array(const int* arr, size_t n) {
    int result = 0;
    for (size_t i = 0; i < n; ++i) {
        result += arr[i];
    }
    return result;
}

constexpr int arr[] = {1, 2, 3, 4, 5};
constexpr int sum = sum_array(arr, 5);  // 15

static_assert(sum == 15, "sum test");

5. constexpr文字列操作

constexpr size_t str_length(const char* str) {
    size_t len = 0;
    while (str[len] != '\0') ++len;
    return len;
}

constexpr bool str_equal(const char* a, const char* b) {
    while (*a && *b && *a == *b) {
        ++a; ++b;
    }
    return *a == *b;
}

constexpr size_t len = str_length("Hello");  // 5
static_assert(str_equal("test", "test"), "equal test");

6. constexpr if (C++17)

template<typename T>
constexpr auto process(T value) {
    if constexpr (is_integral_v<T>) {
        return value * 2;  // 整数は2倍
    } else if constexpr (is_floating_point_v<T>) {
        return value / 2;  // 浮動小数点は半分
    } else {
        return value;  // その他はそのまま
    }
}

constexpr auto int_result = process(10);    // 20
constexpr auto float_result = process(10.0); // 5.0

7. constexpr lambda (C++17)

constexpr auto square = [](int x) { return x * x; };
constexpr auto cube = [](int x) { return x * x * x; };

constexpr int sq = square(5);  // 25
constexpr int cb = cube(3);    // 27

static_assert(square(5) == 25, "square test");

8. コンパイル時アルゴリズム

constexpr bool is_prime(int n) {
    if (n < 2) return false;
    if (n == 2) return true;
    if (n % 2 == 0) return false;
    for (int i = 3; i * i <= n; i += 2) {
        if (n % i == 0) return false;
    }
    return true;
}

constexpr int gcd(int a, int b) {
    while (b != 0) {
        int t = b;
        b = a % b;
        a = t;
    }
    return a;
}

constexpr int lcm(int a, int b) {
    return a / gcd(a, b) * b;
}

static_assert(is_prime(17), "17 is prime");
static_assert(gcd(24, 36) == 12, "gcd test");

9. コンパイル時ルックアップテーブル

template<size_t N>
constexpr array<int, N> make_square_table() {
    array<int, N> result{};
    for (size_t i = 0; i < N; ++i) {
        result[i] = static_cast<int>(i * i);
    }
    return result;
}

template<size_t N>
constexpr array<bool, N> make_prime_sieve() {
    array<bool, N> sieve{};
    for (size_t i = 2; i < N; ++i) {
        sieve[i] = true;
    }
    for (size_t i = 2; i * i < N; ++i) {
        if (sieve[i]) {
            for (size_t j = i * i; j < N; j += i) {
                sieve[j] = false;
            }
        }
    }
    return sieve;
}

// コンパイル時に生成
constexpr auto squares = make_square_table<10>();
constexpr auto primes = make_prime_sieve<30>();

10. constexpr状態機械

enum class State { Start, Running, Paused, Stopped };

constexpr State next_state(State current, bool input) {
    switch (current) {
        case State::Start:   return input ? State::Running : State::Start;
        case State::Running: return input ? State::Paused : State::Stopped;
        case State::Paused:  return input ? State::Running : State::Stopped;
        case State::Stopped: return State::Stopped;
    }
    return State::Stopped;
}

11. コンパイル時バイナリサーチ

constexpr int binary_search(const int* arr, int n, int target) {
    int left = 0, right = n - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) return mid;
        if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

constexpr int arr[] = {1, 3, 5, 7, 9, 11, 13};
constexpr int idx = binary_search(arr, 7, 7);  // 3

実行結果

=== 基本constexpr関数 ===
factorial(5) = 120
fibonacci(10) = 55

=== constexprクラス ===
Point(3,4) + Point(1,2) = (4,6)
Dot product: 11
Manhattan distance: 7

=== constexpr配列操作 ===
Sum: 15
Max: 5

=== constexpr if ===
process(10) = 20
process(10.0) = 5

=== constexpr lambda ===
square(5) = 25
cube(3) = 27

=== constexprアルゴリズム ===
is_prime(7) = 1
gcd(48, 18) = 6
lcm(4, 6) = 12

=== constexprルックアップテーブル ===
Square table: 0 1 4 9 16 25 36 49 64 81
Primes < 30: 2 3 5 7 11 13 17 19 23 29

constexprの進化

バージョン 追加機能
C++11 基本的なconstexpr関数(1文return)
C++14 ループ、ローカル変数、複数文
C++17 constexpr if、constexpr lambda
C++20 constexpr std::vector、virtual関数

まとめ

constexprを活用することで:

  • ランタイムコストをゼロに
  • コンパイル時エラー検出
  • 最適化の促進

モダンC++では積極的にconstexprを使いましょう!

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?