Menu
Coddy logo textTech

constexpr и consteval

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 87 из 104.

C++ позволяет выполнять вычисления во время compile, а не во время выполнения, что может значительно повысить производительность. Ключевое слово constexpr (C++11) и ключевое слово consteval (C++20) дают вам контроль над тем, когда вычисляются выражения.

Функция constexpr может быть вычислена во время компиляции, если ей переданы постоянные аргументы, но она также может выполняться во время выполнения с непостоянными inputs:

#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 должна возвращать constant — вызов её со значениями времени выполнения приведёт к ошибке компиляции:

consteval int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

int main() {
    constexpr int result = factorial(5);  // ОК: 120 вычислено во время компиляции
    
    // int x = 5;
    // int bad = factorial(x);  // ОШИБКА: x не является константой
}

Вы также можете использовать constexpr с переменными и даже конструкторами классов, что позволяет создавать целые объекты во время компиляции. Это особенно полезно для таблиц поиска, значений конфигурации или любых данных, которые не изменяются во время выполнения программы.

challenge icon

Задание

Легко

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

  • MathUtils.h: Define математические functions, вычисляемые во время compile.

    Create следующие functions:

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

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

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

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

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

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

    Затем продемонстрируйте, что functions constexpr также могут работать во время выполнения, используя ваши два входных значения:

    • Выполните Call cube() с первым входным значением и выведите: Cube of [input]: [result]
    • Выполните Call sumOfSquares() с both входными значениями и выведите: 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: 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-функций во время выполнения
    // Вызвать cube() с input1 и вывести: "Cube of [input1]: [result]"
    
    // TODO: Call sumOfSquares() with both inputs
    // and print: "Sum of squares: [result]"
    
    return 0;
}
quiz iconПроверьте себя

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

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

Потренируйтесь самостоятельно: Онлайн-компилятор C++