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
EasyLet'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 sumsubtract(int a, int b)— returns the difference (a - b)multiply(int a, int b)— returns the productpower(int base, int exponent, int multiplier)— returnsmultiplier * (base ^ exponent). Use a simple loop to calculate the power (assume non-negative exponents).
Calculator.h: Define aCalculatorclass that usesstd::functionto 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 operationcalculate(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.- A private member
main.cpp: Read three inputs:- Operation name:
add,subtract,multiply, orsquare - First number (integer)
- Second number (integer)
Create a
Calculatorand configure it based on the operation name:- For
add,subtract, andmultiply: assign the corresponding function directly to the calculator - For
square: usestd::bindto create a specialized version ofpowerthat 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 + 100to the calculator, running it with the same inputs, and printing:With bonus: [value]- Operation name:
For example, with inputs add, 10, and 5:
Result: 15
With bonus: 115With inputs multiply, 7, and 3:
Result: 21
With bonus: 110With inputs square, 4, and 0:
Result: 16
With bonus: 104This 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; }; // Lambdastd::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;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container12Modern C++ Features
Move Semantics & RvaluesPerfect ForwardingLambda Expressions In Depthstd::function & std::bindconstexpr and constevalStructured Bindingsoptional, variant, any