Menu
Coddy logo textTech

std::function & std::bind

Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 86 of 104.

While lambdas are powerful, sometimes you need to store callable objects with different types in a uniform way, or adapt existing functions to match a required signature. std::function and std::bind from the <functional> header solve these problems.

std::function is a type-erased wrapper that can hold any callable matching a specific signature - functions, lambdas, or function objects:

#include <iostream>
#include <functional>

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

int main() {
    std::function<int(int, int)> operation;
    
    operation = add;                              // Regular function
    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 creates a new callable by fixing some arguments of an existing function. Use std::placeholders::_1, _2, etc. to mark arguments that remain variable:

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

These tools are especially useful in OOP for storing callbacks as class members or implementing the Strategy pattern. However, modern C++ often prefers lambdas over std::bind for better readability and performance - use std::bind mainly when you need to reorder arguments or work with legacy code.

challenge icon

Challenge

Easy

Let's build a configurable calculator that demonstrates the power of std::function and std::bind. You'll create a system where mathematical operations can be stored, swapped, and customized at runtime—showing how these tools enable flexible callback management.

You'll organize your code across three files:

  • MathOperations.h: Define a collection of standalone mathematical functions that will serve as your operation library.

    Create these functions:

    • add(int a, int b) — returns the sum
    • subtract(int a, int b) — returns the difference (a - b)
    • multiply(int a, int b) — returns the product
    • power(int base, int exponent, int multiplier) — returns multiplier * (base ^ exponent). Use a simple loop to calculate the power (assume non-negative exponents).
  • Calculator.h: Define a Calculator class that uses std::function to store and execute operations dynamically.

    Your Calculator should have:

    • A private member std::function<int(int, int)> to store the current binary operation
    • setOperation(std::function<int(int, int)> op) — sets the current operation
    • calculate(int a, int b) — executes the stored operation and returns the result

    Include the necessary headers (<functional>) and make sure to include your MathOperations header.

  • main.cpp: Read three inputs:
    1. Operation name: add, subtract, multiply, or square
    2. First number (integer)
    3. Second number (integer)

    Create a Calculator and configure it based on the operation name:

    • For add, subtract, and multiply: assign the corresponding function directly to the calculator
    • For square: use std::bind to create a specialized version of power that always uses exponent 2 and multiplier 1. The bound function should accept two arguments where only the first is used as the base (the second argument can be ignored using a placeholder).

    After setting the operation, call calculate() with your two numbers and print:

    Result: [value]

    Then demonstrate swapping operations by assigning a lambda that returns a + b + 100 to the calculator, running it with the same inputs, and printing:

    With bonus: [value]

For example, with inputs add, 10, and 5:

Result: 15
With bonus: 115

With inputs multiply, 7, and 3:

Result: 21
With bonus: 110

With inputs square, 4, and 0:

Result: 16
With bonus: 104

This challenge shows how std::function provides a uniform way to store different callable types (regular functions, bound functions, and lambdas), while std::bind lets you adapt existing functions by fixing some of their arguments.

Cheat sheet

The <functional> header provides std::function and std::bind for working with callable objects in a flexible way.

std::function is a type-erased wrapper that can store any callable matching a specific signature:

#include <functional>

std::function<int(int, int)> operation;

operation = add;                              // Regular function
operation = [](int a, int b) { return a * b; }; // Lambda

std::bind creates a new callable by fixing some arguments of an existing function. Use std::placeholders::_1, _2, etc. for variable arguments:

#include <functional>

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

using namespace std::placeholders;

auto sayHello = std::bind(greet, "Hello", _1);  // Fix first argument
sayHello("Alice");  // Hello, Alice!

auto swapped = std::bind(greet, _2, _1);  // Reorder arguments
swapped("Bob", "Hi");  // Hi, Bob!

These tools are useful for storing callbacks as class members or implementing flexible callback systems. Modern C++ often prefers lambdas over std::bind for better readability.

Try it yourself

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

using namespace std;

int main() {
    // Read inputs
    string operation;
    int num1, num2;
    cin >> operation >> num1 >> num2;
    
    // Create a Calculator instance
    Calculator calc;
    
    // TODO: Configure the calculator based on the operation name
    // For "add", "subtract", "multiply": assign the corresponding function directly
    // For "square": use std::bind to create a specialized version of power
    //   that always uses exponent 2 and multiplier 1
    //   Hint: Use std::placeholders::_1 for the base argument
    
    if (operation == "add") {
        // Your code here
    } else if (operation == "subtract") {
        // Your code here
    } else if (operation == "multiply") {
        // Your code here
    } else if (operation == "square") {
        // Your code here - use std::bind with power function
    }
    
    // TODO: Call calculate() and print the result
    // Format: "Result: [value]"
    
    // TODO: Demonstrate swapping operations
    // Assign a lambda that returns a + b + 100 to the calculator
    // Call calculate() again and print the result
    // Format: "With bonus: [value]"
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming