Menu
Coddy logo textTech

constexpr i consteval

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 87 z 104.

C++ pozwala wykonywać obliczenia w czasie kompilacji, a nie w czasie działania programu, co może znacznie poprawić wydajność. Słowo kluczowe constexpr (C++11) i słowo kluczowe consteval (C++20) dają Ci kontrolę nad tym, kiedy wyrażenia są obliczane.

Funkcja constexpr może zostać obliczona w czasie kompilacji, jeśli otrzyma stałe argumenty, ale może też działać w czasie wykonywania z argumentami, które nie są stałe:

#include <iostream>

constexpr int square(int n) {
    return n * n;
}

int main() {
    constexpr int compileTime = square(5);  // Obliczane w czasie kompilacji
    
    int x = 7;
    int runtime = square(x);  // Obliczane w czasie wykonywania programu
    
    std::cout << compileTime << "\n";  // 25
    std::cout << runtime << "\n";      // 49
}

Gdy musisz zagwarantować obliczenie podczas kompilacji, użyj consteval. Funkcja consteval musi zwracać stałą — wywołanie jej z wartościami czasu wykonania powoduje błąd kompilacji:

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

int main() {
    constexpr int result = factorial(5);  // OK: 120 obliczone w czasie kompilacji
    
    // int x = 5;
    // int bad = factorial(x);  // ERROR: x nie jest stałą
}

Możesz także używać constexpr ze zmiennymi, a nawet konstruktorami klas, co umożliwia tworzenie całych obiektów na etapie kompilacji. Jest to szczególnie przydatne w przypadku tabel wyszukiwania, wartości konfiguracyjnych lub wszelkich danych, które nie zmieniają się podczas wykonywania programu.

challenge icon

Wyzwanie

Łatwy

Kod zorganizujesz w trzech plikach:

  • MathUtils.h: Zdefiniuj funkcje matematyczne obliczane w czasie kompilacji.

    Utwórz następujące funkcje:

    • cube: funkcja constexpr, która przyjmuje wartość int i zwraca jej sześcian (n * n * n)
    • triangularNumber: funkcja constexpr, która oblicza n-tą liczbę trójkątną przy użyciu wzoru n * (n + 1) / 2. W tym zadaniu wywołujemy ją wyłącznie w kontekście obliczeń w czasie kompilacji, zapisując wynik w zmiennej constexpr.
    • sumOfSquares: funkcja constexpr, która przyjmuje dwie liczby całkowite i zwraca sumę ich kwadratów (a*a + b*b)
  • Config.h: Utwórz strukturę konfiguracji przy użyciu stałych obliczanych w czasie kompilacji.

    Zdefiniuj strukturę Config z konstruktorem constexpr, który przyjmuje trzy liczby całkowite: width, height i depth. Zapisz je jako publiczne składowe. Dodaj również metodę constexpr o nazwie volume(), która zwraca width * height * depth.

    Pod strukturą utwórz globalną stałą constexpr o nazwie DEFAULT_CONFIG, zainicjalizowaną wartościami 10, 20 i 5.

  • main.cpp: Wczytaj z wejścia dwie liczby całkowite reprezentujące wartości określane w czasie wykonywania programu.

    Najpierw zademonstruj obliczenia w czasie kompilacji, tworząc zmienne constexpr:

    • Zapisz cube(4) w zmiennej constexpr i wypisz: Cube of 4: [value]
    • Zapisz triangularNumber(10) w zmiennej constexpr i wypisz: 10th triangular number: [value]
    • Wypisz objętość domyślnej konfiguracji: Default volume: [value]

    Następnie pokaż, że funkcje constexpr mogą działać również w czasie wykonywania programu, używając dwóch wczytanych wartości:

    • Wywołaj cube() z pierwszą wczytaną wartością i wypisz: Cube of [input]: [result]
    • Wywołaj sumOfSquares() z obiema wczytanymi wartościami i wypisz: Sum of squares: [result]

Na przykład dla danych wejściowych 3 i 4:

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

Dla danych wejściowych 5 i 12:

Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 5: 125
Sum of squares: 169

Spróbuj swoich sił

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

using namespace std;

int main() {
    // Wczytaj dwie liczby całkowite z wejścia
    int input1, input2;
    cin >> input1;
    cin >> input2;
    
    // TODO: Zademonstruj obliczanie w czasie kompilacji
    // Utwórz zmienną constexpr przechowującą cube(4) i wypisz: "Cube of 4: [value]"
    
    // TODO: Utwórz zmienną constexpr przechowującą triangularNumber(10)
    // i wypisz: "10th triangular number: [value]"
    
    // TODO: Wypisz głośność domyślnej konfiguracji: "Default volume: [value]"
    
    // TODO: Zademonstruj użycie funkcji constexpr w czasie wykonywania programu
    // Wywołaj cube() z argumentem input1 i wypisz: "Cube of [input1]: [result]"
    
    // TODO: Wywołaj sumOfSquares() z obiema wartościami wejściowymi
    // i wypisz: "Sum of squares: [result]"
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online