Menu
Coddy logo textTech

std::function et std::bind

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

Bien que les lambdas soient puissantes, vous devez parfois stocker des objets appelables de types différents de manière uniforme, ou adapter des fonctions existantes afin qu’elles correspondent à une signature requise. std::function et std::bind de l’en-tête <functional> résolvent ces problèmes.

std::function est une enveloppe avec effacement de type qui peut contenir tout appelable correspondant à une signature spécifique : des fonctions, des lambdas ou des objets fonction :

#include <iostream>
#include <functional>

int add(int a, int b) { return a + b; }

int main() {
    std::function<int(int, int)> operation;
    
    operation = add;                              // Fonction régulière
    std::cout << operation(3, 4) << "\n";        // 7
    
    operation = [](int a, int b) { return a * b; }; // Lambda
    std::cout << operation(3, 4) << "\n";        // 12
}

std::bind crée un nouvel objet appelable en fixant certains arguments d’une fonction existante. Utilisez std::placeholders::_1, _2, etc. pour marquer les arguments qui restent variables :

#include <iostream>
#include <functional>

void greet(const std::string& greeting, const std::string& name) {
    std::cout << greeting << ", " << name << "!\n";
}

int main() {
    using namespace std::placeholders;
    
    auto sayHello = std::bind(greet, "Hello", _1);
    sayHello("Alice");  // Bonjour, Alice !
    
    auto swapped = std::bind(greet, _2, _1);
    swapped("Bob", "Hi");  // Salut, Bob !
}

Ces outils sont particulièrement utiles en POO pour stocker des fonctions de rappel en tant que membres de classe ou pour implémenter le modèle Stratégie. Cependant, le C++ moderne privilégie souvent les lambdas plutôt que std::bind pour une meilleure lisibilité et de meilleures performances : utilisez principalement std::bind lorsque vous devez réordonner les arguments ou travailler avec du code ancien.

challenge icon

Défi

Facile

Construisons une calculatrice configurable qui démontre la puissance de std::function et de std::bind. Vous allez créer un système dans lequel les opérations mathématiques peuvent être stockées, remplacées et personnalisées à l’exécution, montrant ainsi comment ces outils permettent une gestion flexible des rappels.

Vous organiserez votre code sur trois fichiers :

  • MathOperations.h : définissez une collection de fonctions mathématiques autonomes qui serviront de bibliothèque d’opérations.

    Créez ces fonctions :

    • add(int a, int b) : renvoie la somme
    • subtract(int a, int b) : renvoie la différence (a - b)
    • multiply(int a, int b) : renvoie le produit
    • power(int base, int exponent, int multiplier) : renvoie multiplier * (base ^ exponent). Utilisez une boucle simple pour calculer la puissance (en supposant que les exposants sont non négatifs).
  • Calculator.h : définissez une classe Calculator qui utilise std::function pour stocker et exécuter dynamiquement des opérations.

    Votre Calculator doit comporter :

    • Un membre privé std::function<int(int, int)> pour stocker l’opération binaire actuelle
    • setOperation(std::function<int(int, int)> op) : définit l’opération actuelle
    • calculate(int a, int b) : exécute l’opération stockée et renvoie le résultat

    Incluez les en-têtes nécessaires (<functional>) et veillez à inclure votre en-tête MathOperations.

  • main.cpp : lisez trois entrées :
    1. Nom de l’opération : add, subtract, multiply ou square
    2. Premier nombre (entier)
    3. Deuxième nombre (entier)

    Créez un Calculator et configurez-le en fonction du nom de l’opération :

    • Pour add, subtract et multiply : affectez directement la fonction correspondante à la calculatrice
    • Pour square : utilisez std::bind pour créer une version spécialisée de power qui utilise toujours l’exposant 2 et le multiplicateur 1. La fonction liée doit accepter deux arguments, dont seul le premier est utilisé comme base (le deuxième argument peut être ignoré à l’aide d’un paramètre fictif).

    Après avoir défini l’opération, appelez calculate() avec vos deux nombres et affichez :

    Result: [value]

    Démontrez ensuite le remplacement des opérations en affectant à la calculatrice une lambda qui renvoie a + b + 100, exécutez-la avec les mêmes entrées et affichez :

    With bonus: [value]

Par exemple, avec les entrées add, 10 et 5 :

Result: 15
With bonus: 115

Avec les entrées multiply, 7 et 3 :

Result: 21
With bonus: 110

Avec les entrées square, 4 et 0 :

Result: 16
With bonus: 104

Ce défi montre comment std::function fournit une manière uniforme de stocker différents types d’objets appelables (fonctions ordinaires, fonctions liées et lambdas), tandis que std::bind vous permet d’adapter des fonctions existantes en fixant certains de leurs arguments.

Essayez vous-même

#include <iostream>
#include <string>
#include <functional>
#include "Calculator.h"

using namespace std;

int main() {
    // Lire les entrées
    string operation;
    int num1, num2;
    cin >> operation >> num1 >> num2;
    
    // Créer une instance de Calculator
    Calculator calc;
    
    // TODO: Configurer le calculateur en fonction du nom de l'opération
    // Pour "add", "subtract", "multiply" : assigner la fonction correspondante directement
    // Pour "square" : utiliser std::bind pour créer une version spécialisée de power
    //   qui utilise toujours l'exposant 2 et le multiplicateur 1
    //   Astuce : Utiliser std::placeholders::_1 pour l'argument de base
    
    if (operation == "add") {
        // Votre code ici
    } else if (operation == "subtract") {
        // Votre code ici
    } else if (operation == "multiply") {
        // Votre code ici
    } else if (operation == "square") {
        // Votre code ici - utiliser std::bind avec la fonction power
    }
    
    // TODO: Appeler calculate() et afficher le résultat
    // Format : "Result: [value]"
    
    // TODO: Démontrer l'échange des opérations
    // Assignez une lambda qui retourne a + b + 100 au calculateur
    // Appelez calculate() à nouveau et affichez le résultat
    // Format : "With bonus: [value]"
    
    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

Entraînez-vous par vous-même : Compilateur C++ en ligne