Menu
Coddy logo textTech

std::function ve std::bind

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 86 / 104.

Lambdalar güçlü olsa da, bazen farklı türlerdeki çağrılabilir nesneleri tek tip bir şekilde depolamanız veya mevcut fonksiyonları gerekli bir imzaya uyacak şekilde uyarlamanız gerekir. <functional> başlığındaki std::function ve std::bind bu sorunları çözer.

std::function, belirli bir imzaya uyan herhangi bir çağrılabilir öğeyi —fonksiyonlar, lambdalar veya fonksiyon nesneleri— tutabilen tür-silinmiş (type-erased) bir sarmalayıcıdır:

#include <iostream>
#include <functional>

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

int main() {
    std::function<int(int, int)> operation;
    
    operation = add;                              // Normal fonksiyon
    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 mevcut bir fonksiyonun bazı argümanlarını sabitleyerek yeni bir çağrılabilir (callable) oluşturur. Değişken kalan argümanları işaretlemek için std::placeholders::_1, _2 vb. kullanın:

#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!
}

Bu araçlar, callback'leri sınıf üyeleri olarak depolamak veya Strateji desenini (Strategy pattern) uygulamak için OOP'de özellikle yararlıdır. Ancak, modern C++ daha iyi okunabilirlik ve performans için genellikle std::bind yerine lambdaları tercih eder - std::bind'ı esas olarak argümanları yeniden sıralamanız gerektiğinde veya eski (legacy) kodlarla çalışırken kullanın.

challenge icon

Görev

Kolay

std::function ve std::bind'ın gücünü gösteren yapılandırılabilir bir hesap makinesi oluşturalım. Matematiksel işlemlerin çalışma zamanında saklanabildiği, değiştirilebildiği ve özelleştirilebildiği bir sistem oluşturacaksınız; bu, bu araçların esnek geri çağırma (callback) yönetimini nasıl sağladığını gösterecektir.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • MathOperations.h: İşlem kütüphaneniz olarak hizmet edecek bağımsız matematiksel fonksiyonlar koleksiyonu tanımlayın.

    Şu fonksiyonları oluşturun:

    • add(int a, int b) — toplamı döndürür
    • subtract(int a, int b) — farkı döndürür (a - b)
    • multiply(int a, int b) — çarpımı döndürür
    • power(int base, int exponent, int multiplier)multiplier * (base ^ exponent) değerini döndürür. Üssü hesaplamak için basit bir döngü kullanın (üslerin negatif olmadığını varsayın).
  • Calculator.h: İşlemleri dinamik olarak saklamak ve yürütmek için std::function kullanan bir Calculator sınıfı tanımlayın.

    Hesap makineniz şunlara sahip olmalıdır:

    • Mevcut ikili işlemi saklamak için özel (private) bir std::function<int(int, int)> üyesi
    • setOperation(std::function<int(int, int)> op) — mevcut işlemi ayarlar
    • calculate(int a, int b) — saklanan işlemi yürütür ve sonucu döndürür

    Gerekli başlık dosyalarını (<functional>) ekleyin ve MathOperations başlık dosyanızı dahil ettiğinizden emin olun.

  • main.cpp: Üç girdi okuyun:
    1. İşlem adı: add, subtract, multiply veya square
    2. Birinci sayı (tam sayı)
    3. İkinci sayı (tam sayı)

    Bir Calculator oluşturun ve işlem adına göre yapılandırın:

    • add, subtract ve multiply için: ilgili fonksiyonu doğrudan hesap makinesine atayın
    • square için: her zaman 2 üssünü ve 1 çarpanını kullanan özelleştirilmiş bir power sürümü oluşturmak için std::bind kullanın. Bağlanan fonksiyon, yalnızca birincisinin taban olarak kullanıldığı iki argüman kabul etmelidir (ikinci argüman bir yer tutucu kullanılarak yoksayılabilir).

    İşlemi ayarladıktan sonra, iki sayınızla calculate() fonksiyonunu çağırın ve şunu yazdırın:

    Result: [value]

    Ardından, hesap makinesine a + b + 100 döndüren bir lambda atayarak, aynı girdilerle çalıştırarak ve şunu yazdırarak işlem değiştirme işlemini gösterin:

    With bonus: [value]

Örneğin, add, 10 ve 5 girdileriyle:

Result: 15
With bonus: 115

multiply, 7 ve 3 girdileriyle:

Result: 21
With bonus: 110

square, 4 ve 0 girdileriyle:

Result: 16
With bonus: 104

Bu zorluk, std::function'ın farklı çağrılabilir türleri (normal fonksiyonlar, bağlanmış fonksiyonlar ve lambdalar) saklamak için nasıl tek tip bir yol sağladığını, std::bind'ın ise mevcut fonksiyonları bazı argümanlarını sabitleyerek uyarlamanıza nasıl izin verdiğini gösterir.

Kendin dene

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

using namespace std;

int main() {
    // Girdileri oku
    string operation;
    int num1, num2;
    cin >> operation >> num1 >> num2;
    
    // Bir Calculator örneği oluştur
    Calculator calc;
    
    // YAPILACAK: İşlem adına göre hesap makinesini yapılandırın
    // "add", "subtract", "multiply" için: ilgili fonksiyonu doğrudan atayın
    // "square" için: power fonksiyonunun özelleştirilmiş bir versiyonunu oluşturmak için std::bind kullanın
    //   her zaman 2 üssünü ve 1 çarpanını kullanan
    //   İpucu: Taban argümanı için std::placeholders::_1 kullanın
    
    if (operation == "add") {
        // Kodunuz buraya
    } else if (operation == "subtract") {
        // Kodunuz buraya
    } else if (operation == "multiply") {
        // Kodunuz buraya
    } else if (operation == "square") {
        // Kodunuz buraya - power fonksiyonu ile std::bind kullanın
    }
    
    // YAPILACAK: calculate() fonksiyonunu çağırın ve sonucu yazdırın
    // Format: "Result: [değer]"
    
    // YAPILACAK: İşlem değiştirmeyi gösterin
    // Hesap makinesine a + b + 100 döndüren bir lambda atayın
    // calculate() fonksiyonunu tekrar çağırın ve sonucu yazdırın
    // Format: "With bonus: [değer]"
    
    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler