Menu
Coddy logo textTech

std::function i std::bind

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

Chociaż lambdy są potężne, czasami trzeba przechowywać wywoływalne obiekty różnych typów w jednolity sposób albo dostosować istniejące funkcje do wymaganego podpisu. std::function i std::bind z nagłówka <functional> rozwiązują te problemy.

std::function to opakowanie z wymazanym typem, które może przechowywać dowolny obiekt wywoływalny zgodny z określoną sygnaturą — funkcje, lambdy lub obiekty funkcyjne:

#include <iostream>
#include <functional>

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

int main() {
    std::function<int(int, int)> operation;
    
    operation = add;                              // Zwykła funkcja
    std::cout << operation(3, 4) << "\n";        // 7
    
    operation = [](int a, int b) { return a * b; }; // Funkcja lambda
    std::cout << operation(3, 4) << "\n";        // 12
}

std::bind tworzy nowy obiekt wywoływalny, ustalając niektóre argumenty istniejącej funkcji. Użyj std::placeholders::_1, _2 itd., aby oznaczyć argumenty, które pozostają zmienne:

#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");  // Hello, Alice!
    
    auto swapped = std::bind(greet, _2, _1);
    swapped("Bob", "Hi");  // Hi, Bob!
}

Te narzędzia są szczególnie przydatne w programowaniu obiektowym do przechowywania funkcji zwrotnych jako składowych klasy lub implementowania wzorca Strategia. Jednak we współczesnym C++ często preferuje się lambdy zamiast std::bind ze względu na lepszą czytelność i wydajność — używaj std::bind głównie wtedy, gdy musisz zmienić kolejność argumentów lub pracujesz ze starszym kodem.

challenge icon

Wyzwanie

Łatwy

Zbudujmy konfigurowalny kalkulator, który demonstruje możliwości std::function i std::bind. Utworzysz system, w którym operacje matematyczne można przechowywać, zamieniać i dostosowywać w czasie działania programu, pokazując, jak te narzędzia umożliwiają elastyczne zarządzanie funkcjami zwrotnymi.

Podzielisz swój kod na trzy pliki:

  • MathOperations.h: Zdefiniuj zbiór samodzielnych funkcji matematycznych, które będą pełnić rolę biblioteki operacji.

    Utwórz następujące funkcje:

    • add(int a, int b): zwraca sumę
    • subtract(int a, int b): zwraca różnicę (a - b)
    • multiply(int a, int b): zwraca iloczyn
    • power(int base, int exponent, int multiplier): zwraca multiplier * (base ^ exponent). Użyj prostej pętli do obliczenia potęgi (załóż nieujemne wykładniki).
  • Calculator.h: Zdefiniuj klasę Calculator, która używa std::function do dynamicznego przechowywania i wykonywania operacji.

    Twój kalkulator powinien mieć:

    • Prywatne pole std::function<int(int, int)> do przechowywania bieżącej operacji dwuargumentowej
    • setOperation(std::function<int(int, int)> op): ustawia bieżącą operację
    • calculate(int a, int b): wykonuje przechowywaną operację i zwraca wynik

    Dołącz niezbędne nagłówki (<functional>) i pamiętaj o dołączeniu nagłówka MathOperations.

  • main.cpp: Wczytaj trzy dane wejściowe:
    1. Nazwę operacji: add, subtract, multiply lub square
    2. Pierwszą liczbę (liczbę całkowitą)
    3. Drugą liczbę (liczbę całkowitą)

    Utwórz obiekt Calculator i skonfiguruj go na podstawie nazwy operacji:

    • Dla add, subtract i multiply: przypisz odpowiednią funkcję bezpośrednio do kalkulatora
    • Dla square: użyj std::bind, aby utworzyć wyspecjalizowaną wersję funkcji power, która zawsze używa wykładnika 2 i mnożnika 1. Powiązana funkcja powinna przyjmować dwa argumenty, z których tylko pierwszy jest używany jako podstawa (drugi argument można zignorować za pomocą symbolu zastępczego).

    Po ustawieniu operacji wywołaj calculate() z podanymi dwiema liczbami i wyświetl:

    Result: [value]

    Następnie zademonstruj zmianę operacji, przypisując kalkulatorowi lambdę, która zwraca a + b + 100, uruchamiając ją z tymi samymi danymi wejściowymi i wyświetlając:

    With bonus: [value]

Na przykład dla danych wejściowych add, 10 i 5:

Result: 15
With bonus: 115

Dla danych wejściowych multiply, 7 i 3:

Result: 21
With bonus: 110

Dla danych wejściowych square, 4 i 0:

Result: 16
With bonus: 104

To wyzwanie pokazuje, jak std::function zapewnia jednolity sposób przechowywania różnych typów obiektów wywoływalnych (zwykłych funkcji, funkcji powiązanych i lambd), a std::bind pozwala dostosowywać istniejące funkcje przez ustalenie niektórych ich argumentów.

Spróbuj swoich sił

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

using namespace std;

int main() {
    // Wczytaj dane wejściowe
    string operation;
    int num1, num2;
    cin >> operation >> num1 >> num2;
    
    // Utwórz instancję Calculator
    Calculator calc;
    
    // TODO: Skonfiguruj kalkulator na podstawie nazwy operacji
    // Dla "add", "subtract", "multiply": przypisz bezpośrednio odpowiednią funkcję
    // Dla "square": użyj std::bind, aby utworzyć wyspecjalizowaną wersję funkcji power
    //   która zawsze używa wykładnika 2 i mnożnika 1
    //   Wskazówka: użyj std::placeholders::_1 jako argumentu podstawy
    
    if (operation == "add") {
        // Twój kod tutaj
    } else if (operation == "subtract") {
        // Twój kod tutaj
    } else if (operation == "multiply") {
        // Twój kod tutaj
    } else if (operation == "square") {
        // Twój kod tutaj — użyj std::bind z funkcją power
    }
    
    // TODO: Wywołaj calculate() i wypisz wynik
    // Format: "Result: [value]"
    
    // TODO: Zademonstruj zamianę operacji
    // Przypisz kalkulatorowi lambdę, która zwraca a + b + 100
    // Ponownie wywołaj calculate() i wypisz wynik
    // Format: "With bonus: [value]"
    
    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