Menu
Coddy logo textTech

constexpr и consteval

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 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 с переменными и даже конструкторами классов, что позволяет создавать целые объекты во время компиляции. Это особенно полезно для таблиц поиска, конфигурационных значений или любых данных, которые не изменяются во время выполнения программы.

challenge icon

Задание

Легко

Вы организуете свой код в трех файлах:

  • MathUtils.h: Определите математические функции времени компиляции.

    Создайте следующие функции:

    • cube — функция constexpr, которая принимает int и возвращает его куб (n * n * n)
    • triangularNumber — функция constexpr, которая вычисляет n-ое треугольное число по формуле n * (n + 1) / 2. В этом задании мы вызываем ее только в контексте времени компиляции, сохраняя результат в переменной constexpr.
    • sumOfSquares — функция constexpr, которая принимает два целых числа и возвращает сумму их квадратов (a*a + b*b)
  • Config.h: Создайте структуру конфигурации, используя константы времени компиляции.

    Определите структуру Config с конструктором constexpr, который принимает три целых числа: width, height и depth. Сохраните их как публичные члены. Также добавьте метод constexpr с именем volume(), который возвращает width * height * depth.

    Под структурой создайте глобальную константу constexpr с именем DEFAULT_CONFIG, инициализированную значениями 10, 20 и 5.

  • main.cpp: Считайте два целых числа из входных данных, представляющих значения времени выполнения.

    Сначала продемонстрируйте вычисление во время компиляции, создав переменные constexpr:

    • Сохраните cube(4) в переменной constexpr и выведите: Cube of 4: [value]
    • Сохраните triangularNumber(10) в переменной constexpr и выведите: 10th triangular number: [value]
    • Выведите объем конфигурации по умолчанию: Default volume: [value]

    Затем продемонстрируйте, что функции 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

Попробуйте сами

#include <iostream>
#include "MathUtils.h"
#include "Config.h"

using namespace std;

int main() {
    // Чтение двух целых чисел из входного потока
    int input1, input2;
    cin >> input1;
    cin >> input2;
    
    // TODO: Продемонстрировать вычисление во время компиляции
    // Создать переменную constexpr, хранящую cube(4), и вывести: "Cube of 4: [value]"
    
    // TODO: Создать переменную constexpr, хранящую triangularNumber(10)
    // и вывести: "10th triangular number: [value]"
    
    // TODO: Вывести громкость конфигурации по умолчанию: "Default volume: [value]"
    
    // TODO: Продемонстрировать использование constexpr функций во время выполнения
    // Вызвать cube() с input1 и вывести: "Cube of [input1]: [result]"
    
    // TODO: Вызвать sumOfSquares() с обоими входными данными
    // и вывести: "Sum of squares: [result]"
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование