Menu
Coddy logo textTech

constexpr et consteval

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 87 sur 104.

Le C++ permet d'effectuer des calculs au temps de compilation plutôt qu'à l'exécution, ce qui peut améliorer considérablement les performances. Le mot-clé constexpr (C++11) et le mot-clé consteval (C++20) vous permettent de contrôler le moment où les expressions sont évaluées.

Une fonction constexpr peut être évaluée au moment de la compilation si elle reçoit des arguments constants, mais elle peut également s'exécuter au moment de l'exécution avec des entrées non constantes :

#include <iostream>

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

int main() {
    constexpr int compileTime = square(5);  // Évalué à la compilation
    
    int x = 7;
    int runtime = square(x);  // Évalué à l'exécution
    
    std::cout << compileTime << "\n";  // 25
    std::cout << runtime << "\n";      // 49
}

Lorsque vous avez besoin de garantir l'évaluation à la compilation, utilisez consteval. Une fonction consteval doit produire une constante - l'appeler avec des valeurs d'exécution est une erreur de compilation :

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

int main() {
    constexpr int result = factorial(5);  // OK : 120 calculé au moment de la compilation
    
    // int x = 5;
    // int bad = factorial(x);  // ERREUR : x n'est pas une constante
}

Vous pouvez également utiliser constexpr avec des variables et même des constructeurs de classe, permettant à des objets entiers d'être créés au moment de la compilation. Ceci est particulièrement utile pour les tables de correspondance, les valeurs de configuration ou toute donnée qui ne change pas pendant l'exécution du programme.

challenge icon

Défi

Facile

Vous organiserez votre code sur trois fichiers :

  • MathUtils.h : Définissez vos fonctions mathématiques évaluables à la compilation.

    Créez les fonctions suivantes :

    • cube — une fonction constexpr qui prend un int et retourne son cube (n * n * n)
    • triangularNumber — une fonction constexpr qui calcule le n-ième nombre triangulaire en utilisant la formule n * (n + 1) / 2. Celle-ci doit toujours être évaluée au moment de la compilation.
    • sumOfSquares — une fonction constexpr qui prend deux entiers et retourne la somme de leurs carrés (a*a + b*b)
  • Config.h : Créez une structure de configuration utilisant des constantes de compilation.

    Définissez une structure Config avec un constructeur constexpr qui prend trois entiers : width, height, et depth. Stockez-les en tant que membres publics. Ajoutez également une méthode constexpr appelée volume() qui retourne width * height * depth.

    Sous la structure, créez une constante globale constexpr appelée DEFAULT_CONFIG initialisée avec les valeurs 10, 20 et 5.

  • main.cpp : Lisez deux entiers à partir de l'entrée représentant des valeurs d'exécution.

    Tout d'abord, démontrez l'évaluation à la compilation en créant des variables constexpr :

    • Stockez cube(4) dans une variable constexpr et affichez : Cube of 4: [value]
    • Stockez triangularNumber(10) dans une variable constexpr et affichez : 10th triangular number: [value]
    • Affichez le volume de la configuration par défaut : Default volume: [value]

    Ensuite, démontrez que les fonctions constexpr peuvent également fonctionner à l'exécution en utilisant vos deux valeurs d'entrée :

    • Appelez cube() avec la première entrée et affichez : Cube of [input]: [result]
    • Appelez sumOfSquares() avec les deux entrées et affichez : Sum of squares: [result]

Par exemple, avec les entrées 3 et 4 :

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

Avec les entrées 5 et 12 :

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

Aide-mémoire

Le C++ permet d'effectuer des calculs au moment de la compilation en utilisant les mots-clés constexpr (C++11) et consteval (C++20).

Une fonction constexpr peut être évaluée au moment de la compilation avec des arguments constants, mais s'exécute également au moment de l'exécution avec des entrées non constantes :

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

constexpr int compileTime = square(5);  // Évalué au moment de la compilation

int x = 7;
int runtime = square(x);  // Évalué au moment de l'exécution

Une fonction consteval doit être évaluée au moment de la compilation. L'appeler avec des valeurs d'exécution provoque une erreur de compilation :

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

constexpr int result = factorial(5);  // OK : calculé au moment de la compilation

// int x = 5;
// int bad = factorial(x);  // ERREUR : x n'est pas une constante

Vous pouvez utiliser constexpr avec des variables, des constructeurs de classe et des méthodes pour permettre la création d'objets au moment de la compilation :

struct Config {
    int width, height, depth;
    
    constexpr Config(int w, int h, int d) 
        : width(w), height(h), depth(d) {}
    
    constexpr int volume() const {
        return width * height * depth;
    }
};

constexpr Config config(10, 20, 5);  // Créé au moment de la compilation

Essayez vous-même

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

using namespace std;

int main() {
    // Lire deux entiers depuis l'entrée
    int input1, input2;
    cin >> input1;
    cin >> input2;
    
    // TODO: Démontrer l'évaluation au moment de la compilation
    // Créer une variable constexpr stockant cube(4) et afficher : "Cube of 4: [value]"
    
    // TODO: Créer une variable constexpr stockant triangularNumber(10)
    // et afficher : "10th triangular number: [value]"
    
    // TODO: Afficher le volume de la configuration par défaut : "Default volume: [value]"
    
    // TODO: Démontrer l'utilisation au moment de l'exécution des fonctions constexpr
    // Appeler cube() avec input1 et afficher : "Cube of [input1]: [result]"
    
    // TODO: Appeler sumOfSquares() avec les deux entrées
    // et afficher : "Sum of squares: [result]"
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet