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.
Wyzwanie
ŁatwyKod zorganizujesz w trzech plikach:
MathUtils.h: Zdefiniuj funkcje matematyczne obliczane w czasie kompilacji.Utwórz następujące funkcje:
cube: funkcjaconstexpr, która przyjmuje wartośćinti zwraca jej sześcian (n * n * n)triangularNumber: funkcjaconstexpr, 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 zmiennejconstexpr.sumOfSquares: funkcjaconstexpr, 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ę
Configz konstruktoremconstexpr, który przyjmuje trzy liczby całkowite:width,heightidepth. Zapisz je jako publiczne składowe. Dodaj również metodęconstexpro nazwievolume(), która zwraca width * height * depth.Pod strukturą utwórz globalną stałą
constexpro nazwieDEFAULT_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
constexprmogą 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]
- Zapisz
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: 25Dla danych wejściowych 5 i 12:
Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 5: 125
Sum of squares: 169Spró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;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneBudowanie i kompilacja C++Pliki nagłówkowe i pliki źródłowePrzestrzenie nazw i zakresWprowadzenie do programowania obiektowego w C++Klasy a obiektyWskaźnik „this”Metody (funkcje składowe)Atrybuty (składowe danych)Podstawy konstruktorów i destruktorówPowtórzenie – prosty kalkulator4Właściwości klas
Elementy instancji a elementy statyczneGettery i setteryStałe funkcje składoweSłowo kluczowe mutableMetody i zmienne statyczneFunkcje i klasy zaprzyjaźnionePodsumowanie – menedżer konta bankowego7Dziedziczenie
Podstawy dziedziczeniaPoziomy dostępu w dziedziczeniuKolejność wywołań konstruktora i destruktoraNadpisywanie metodFunkcje wirtualne i VTableWielokrotne dziedziczenieDziedziczenie wirtualnePowtórzenie — hierarchia pracowników2Zarządzanie pamięcią
Pamięć stosu a stertyWskaźniki i referencjePamięć dynamiczna (new/delete)Inteligentne wskaźniki w C++RAII w C++Podsumowanie — menedżer tablicy dynamicznej5Hermetyzacja
Specyfikatory dostępu w C++Specyfikatory dostępu — szczegółowoUkrywanie informacjiStruktura a klasaKlasy zagnieżdżone i wewnętrznePodsumowanie — system ewidencji studentów8Polimorfizm
Polimorfizm czasu kompilacji i wykonaniaPrzeciążanie funkcjiFunkcje wirtualne — powtórkaCzysto wirtualne funkcjeKlasy abstrakcyjneProjektowanie interfejsów w C++Rzutowanie dynamiczne i RTTIPodsumowanie — kalkulator kształtów3Konstruktory i destruktory
Konstruktor domyślnyKonstruktor z parametramiKonstruktor kopiującyKonstruktor przenoszącyListy inicjalizacyjne konstruktoraKonstruktory delegująceDestruktor — szczegółowe omówienieZasada trzech / pięciu / zeraPodsumowanie — klasa String6Przeciążanie operatorów
Wprowadzenie do przeciążania operatorówPrzeciążanie operatorów arytmetycznychPrzeciążanie operatorów porównaniaOperatory strumieniowePrzeciążanie operatora przypisaniaPrzeciążanie operatorów [] i ()Operatory konwersji typówPodsumowanie — klasa Matrix9Szablony
Szablony funkcjiSzablony klasSpecjalizacja szablonówSzablony wariadycznePodstawy SFINAE i cech typówPodsumowanie — kontener generyczny12Nowoczesne funkcje C++
Semantyka przenoszenia i r-wartościDoskonałe przekazywanieWyrażenia lambda w szczegółachstd::function i std::bindconstexpr i constevalWiązania strukturalneoptional, variant, anyPoćwicz samodzielnie: Kompilator C++ online