Article by Ayman Alheraki on April 4 2026 04:09 PM
The <functional> header is one of the most powerful and versatile parts of the C++ Standard Library. It provides tools for working with callable objects – things you can invoke like functions. Whether you're using lambdas, function pointers, functors, or member functions, <functional> helps you store, bind, adapt, and pass them around seamlessly.
In this article, we’ll explore every major component of <functional> with clear, practical examples. By the end, you’ll know how to use std::function, std::bind, placeholders, std::reference_wrapper, std::mem_fn, and more.
<functional>?At its core, <functional> provides:
Polymorphic function wrappers (std::function) – a type‑erased container for any callable.
Function binders (std::bind, placeholders) – to fix arguments or reorder them.
Reference wrappers (std::reference_wrapper, std::ref, std::cref) – to store references in copy‑heavy contexts.
Member function adapters (std::mem_fn) – to turn member functions into ordinary function objects.
Function objects for arithmetic, comparisons, and logical operations (e.g., std::plus, std::greater, std::logical_and).
All of these are designed to work seamlessly with the <algorithm> library and modern C++ idioms.
std::function – The Universal Callable Wrapperstd::function is a type‑erased wrapper that can hold any callable object with a given signature. It’s like a super‑charged function pointer.
cpp
x
int add(int a, int b) { return a + b; }
struct Multiply { int operator()(int a, int b) const { return a * b; }};
int main() { // Store a free function std::function<int(int,int)> func = add; std::cout << func(3, 4) << '\n'; // 7
// Store a lambda func = [](int a, int b) { return a - b; }; std::cout << func(10, 3) << '\n'; // 7
// Store a functor (function object) Multiply mult; func = mult; std::cout << func(5, 6) << '\n'; // 30
return 0;}
std::function?Type erasure – you can store different callables in the same container (e.g., std::vector<std::function<bool(int,int)>>).
Nullability – a std::function can be empty; test it with !func or func == nullptr.
Target access – use func.target<T>() to retrieve the stored object (advanced).
std::function has some overhead (virtual dispatch, possible small‑object optimisation). For hot paths, consider using templates or raw function pointers. But for callbacks, event systems, or configuration, it’s invaluable.
cpp
xxxxxxxxxx
class Button { std::vector<std::function<void()>> clickHandlers;public: void onClick(std::function<void()> handler) { clickHandlers.push_back(handler); } void click() { for (auto& h : clickHandlers) h(); }};
void playSound() { /* ... */ }
int main() { Button btn; btn.onClick(playSound); btn.onClick([](){ std::cout << "Button clicked!\n"; }); btn.click(); // calls both}
std::bind – Fixing and Reordering ArgumentsBefore lambdas (C++11), std::bind was the main way to create adapters. Today, lambdas are often clearer, but std::bind still shines in generic code or when you need to bind member functions.
cpp
xxxxxxxxxxauto newCallable = std::bind(callable, arg1, arg2, ..., argN);
Placeholders _1, _2, … (from std::placeholders) represent arguments that will be supplied when the bound object is called.
cpp
xxxxxxxxxx
void print(int a, int b, int c) { std::cout << a << ", " << b << ", " << c << '\n';}
int main() { using namespace std::placeholders;
// Fix the first argument to 10 auto f1 = std::bind(print, 10, _1, _2); f1(20, 30); // prints: 10, 20, 30
// Reorder arguments: third becomes first, etc. auto f2 = std::bind(print, _3, _1, _2); f2(1, 2, 3); // prints: 3, 1, 2
// Bind a member function (requires an object pointer) struct Demo { void say(int x) { std::cout << x << '\n'; } }; Demo d; auto f3 = std::bind(&Demo::say, &d, _1); f3(42); // prints: 42}
std::bind Over Lambda?Very generic code – std::bind works with any callable, including member pointers, without needing std::mem_fn.
Perfect forwarding of placeholders – lambdas require decltype tricks.
Compile‑time argument reordering – sometimes more concise than a lambda.
But lambdas are generally more readable. For new code, use lambdas unless you have a specific reason.
_1, _2, _3, …Placeholders live in the std::placeholders namespace. They tell std::bind which arguments to forward and where.
cpp
xxxxxxxxxx
void show(int a, int b) { std::cout << a << ' ' << b << '\n'; }
int main() { using namespace std::placeholders;
auto f = std::bind(show, _2, _1); // swap arguments f(100, 200); // prints: 200 100
// You can also ignore arguments: use _1 for unused position auto g = std::bind(show, 42, _2); // ignores first argument g(999, 123); // prints: 42 123}
std::ref and std::cref – Reference WrappersBy default, std::bind and std::function copy their arguments. To store or pass a reference, use std::ref (non‑const) or std::cref (const). They create a std::reference_wrapper<T>.
cpp
xxxxxxxxxx
void increment(int& x) { ++x; }
int main() { int a = 5; auto bad = std::bind(increment, a); // copies 'a'! bad(); std::cout << a << '\n'; // still 5 – not incremented
auto good = std::bind(increment, std::ref(a)); good(); std::cout << a << '\n'; // 6 – works!}
std::ref with std::functioncpp
xxxxxxxxxxstd::function<void()> f = std::bind(increment, std::ref(a));
You can also store a reference wrapper directly:
cpp
xxxxxxxxxxstd::reference_wrapper<int> refA = std::ref(a);refA.get() = 10; // modifies a
std::crefWhen you want to pass a const reference, e.g., to avoid copying a large object into a lambda or bound callable.
cpp
xxxxxxxxxxvoid process(const std::string& s);std::string huge = "...";auto bound = std::bind(process, std::cref(huge)); // no copy
std::mem_fn – Wrapping Member Functionsstd::mem_fn turns a pointer to a member function into a callable object that can be invoked with an object (or pointer) as the first argument.
cpp
xxxxxxxxxxauto wrapper = std::mem_fn(&Class::method);wrapper(object, args...);wrapper(&object, args...);
cpp
xxxxxxxxxx
struct Person { std::string name; void greet() const { std::cout << "Hello, I'm " << name << '\n'; } void setAge(int a) { age = a; } int age = 0;};
int main() { std::vector<Person> people = {{"Alice"}, {"Bob"}};
// Call const member on each object auto greetFn = std::mem_fn(&Person::greet); for (Person& p : people) greetFn(p); // Alice, then Bob
// Use with std::for_each std::for_each(people.begin(), people.end(), greetFn);
// Non‑const member with pointer auto setAgeFn = std::mem_fn(&Person::setAge); Person alice{"Alice"}; setAgeFn(&alice, 30); // passes pointer setAgeFn(alice, 31); // also works with reference}
std::bind & Lambdasstd::mem_fn is cleaner than std::bind(&Person::greet, _1).
Lambdas are equally clear: [&](Person& p){ p.greet(); }.
Use std::mem_fn when you already have a callable object and want to pass it to an algorithm without extra braces.
The <functional> header provides templated functors for common operations. These are useful with std::transform, std::sort, etc., and often allow the compiler to inline better than a hand‑rolled lambda.
| Functor | Operation |
|---|---|
std::plus<T> | + |
std::minus<T> | - |
std::multiplies<T> | * |
std::divides<T> | / |
std::modulus<T> | % |
std::negate<T> | - (unary) |
| Functor | Operation |
|---|---|
std::equal_to<T> | == |
std::not_equal_to<T> | != |
std::greater<T> | > |
std::less<T> | < |
std::greater_equal<T> | >= |
std::less_equal<T> | <= |
| Functor | Operation |
|---|---|
std::logical_and<T> | && |
std::logical_or<T> | || |
std::logical_not<T> | ! |
cpp
xxxxxxxxxx
int main() { std::vector<int> v = {3, 1, 4, 1, 5}; // Sort in descending order std::sort(v.begin(), v.end(), std::greater<int>()); // v = {5,4,3,1,1}
// Transform: multiply each element by 2 std::vector<int> result; std::transform(v.begin(), v.end(), std::back_inserter(result), std::bind(std::multiplies<int>(), std::placeholders::_1, 2)); // result = {10,8,6,2,2}
// Using plus with accumulate int sum = std::accumulate(v.begin(), v.end(), 0, std::plus<int>()); std::cout << sum << '\n'; // 14}
std::function with Move‑Only Typesstd::function requires the stored callable to be copy‑constructible. For move‑only callables (e.g., a lambda capturing a std::unique_ptr), you need a different approach – like std::move_only_function (C++23) or a custom wrapper. In C++14/17, you can use std::packaged_task or design your own type‑erased interface.
cpp
xxxxxxxxxx// C++23 example (not yet widely supported)std::move_only_function<void()> f = [ptr = std::make_unique<int>(42)]() { /*...*/ };
| Tool | Use case |
|---|---|
| Raw function pointer | Very lightweight, no capture, fixed signature. |
| Lambda (auto) | Most local uses, best optimisation. |
std::function | Storing heterogeneous callables, callbacks, type erasure needed. |
std::bind | Legacy code or advanced perfect‑forwarding scenarios. |
std::mem_fn | When you need a callable for a member function, especially in generic algorithms. |
std::ref / std::cref | Any time you want to avoid copying into a bind/function. |
| Built‑in functors | For standard operations, often faster than lambdas (compiler knows them). |
std::functioncpp
xxxxxxxxxx// Bad (overhead for no reason)void forEach(const std::vector<int>& v, std::function<void(int)> f) { ... }
// Good (template, zero overhead)template<typename F>void forEach(const std::vector<int>& v, F f) { ... }
std::function typically stores small callables (e.g., a lambda with no captures) inline, avoiding heap allocation. For larger objects, it allocates on the heap.
Let’s tie everything together in a small event dispatcher.
cpp
xxxxxxxxxx
class EventDispatcher { using Handler = std::function<void(const std::string&, int)>; std::multimap<std::string, Handler> handlers;
public: void subscribe(const std::string& event, Handler h) { handlers.emplace(event, std::move(h)); }
void emit(const std::string& event, int value) { auto range = handlers.equal_range(event); for (auto it = range.first; it != range.second; ++it) { it->second(event, value); } }};
struct Logger { void log(const std::string& ev, int val) const { std::cout << "[Logger] " << ev << " -> " << val << '\n'; }};
int main() { EventDispatcher dispatcher;
// Lambda handler dispatcher.subscribe("click", [](const std::string& e, int v) { std::cout << "Lambda: " << e << " with " << v << '\n'; });
// Free function handler auto freeHandler = [](const std::string& e, int v) { std::cout << "Free: " << e << " = " << v << '\n'; }; dispatcher.subscribe("update", freeHandler);
// Member function using bind and ref Logger logger; dispatcher.subscribe("log", std::bind(&Logger::log, &logger, std::placeholders::_1, std::placeholders::_2));
// Emit events dispatcher.emit("click", 42); dispatcher.emit("update", 100); dispatcher.emit("log", 99);}
Output:
text
xxxxxxxxxxLambda: click with 42Free: update = 100[Logger] log -> 99
#include <functional> is an essential tool for modern C++ developers. It provides:
std::function for type‑erased callables,
std::bind and placeholders for argument adaptation,
std::ref / std::cref for reference semantics,
std::mem_fn for member function pointers,
Convenient function objects for standard operations.
While lambdas have replaced many uses of std::bind, the <functional> header remains indispensable for writing flexible, generic, and expressive C++ code. Use it wisely, and your callbacks, algorithms, and event systems will become both powerful and clear.
Now go ahead – #include <functional> and unleash the full potential of callable objects in C++!