std::function
A general-purpose polymorphic function wrapper that type-erases any callable matching a given signature, at the cost of runtime overhead.
std::functionsince C++11A type-erasing wrapper in <functional> that stores any callable β lambda, free function, member function pointer, or functor β whose call signature matches R(Args...), enabling heterogeneous storage and runtime reassignment at the cost of heap allocation and indirect dispatch.
Overview
std::function<R(Args...)> solves a concrete problem: you need a variable, struct member, or container element that can hold any callable with a specific signature, where the concrete callable type is not known until runtime. Classic use cases include event handlers, strategy callbacks stored in objects, and command queues.
The mechanism is type erasure via an internal vtable. When you assign a callable to std::function, it stores a copy of the callable in heap-allocated memory (unless it fits in a small internal buffer β SBO, typically 16β32 bytes depending on the implementation), and records virtual-dispatch pointers for invoke, copy, destroy, and type-info operations.
This flexibility is not free:
- Heap allocation occurs for callables larger than the SBO threshold.
- Indirect call through a vtable pointer prevents inlining.
- Copy semantics require the wrapped callable to be copyable β
std::functionis itself copyable and stores a copy of the callable.
For compile-time-known callables (the common case in performance-sensitive code), prefer template parameters or auto β zero overhead, fully inlinable.
Syntax
#include <functional>
// Declaration
std::function<ReturnType(Param1, Param2, ...)> f;
// Assign any matching callable
f = some_lambda;
f = &free_function;
f = functor_instance;
f = std::bind(...); // C++11, mostly superseded by lambdas
// Invoke
R result = f(arg1, arg2);
// Check empty (default-constructed or assigned nullptr)
if (f) { f(); } // safe
f(); // throws std::bad_function_call if empty
// Reset
f = nullptr;The template argument is a function type, not a function pointer type. std::function<void(int)> takes a function type void(int) β analogous to using Sig = void(int), not void(*)(int).
Examples
Storing heterogeneous callables
#include <functional>
#include <vector>
#include <print>
// Pipeline of transforms β different callable types, uniform interface
std::vector<std::function<int(int)>> pipeline;
pipeline.push_back([](int n) { return n * 2; }); // lambda
pipeline.push_back([factor = 10](int n){ return n + factor; }); // capturing lambda
pipeline.push_back(std::negate<int>{}); // functor (C++11)
int value = 3;
for (auto& fn : pipeline) value = fn(value);
// 3 β 6 β 16 β -16
std::println("{}", value); // C++23Wrapping member functions
Member functions cannot be assigned directly to std::function<R(Args...)> without explicitly accounting for the implicit this parameter. Two patterns:
struct Timer {
int interval_ms = 100;
void on_tick() { std::println("tick at {}ms", interval_ms); }
};
Timer t;
// Pattern 1: capture in lambda β binds lifetime to t
std::function<void()> cb1 = [&t]{ t.on_tick(); };
// Pattern 2: signature includes the object parameter
std::function<void(Timer&)> cb2 = &Timer::on_tick;
cb2(t); // calls t.on_tick()
// Pattern 3: std::bind β C++11, avoid in new code
auto cb3 = std::bind(&Timer::on_tick, &t); // stores raw pointer β watch lifetimeStrategy pattern via struct member
struct Renderer {
std::function<void(float, float, float)> draw_primitive;
void render_scene() {
if (draw_primitive) draw_primitive(0.f, 0.f, 1.f);
}
};
Renderer r;
r.draw_primitive = [](float x, float y, float z) {
// OpenGL path
};
// Swap strategy at runtime without inheritance
r.draw_primitive = [](float x, float y, float z) {
// Vulkan path
};Recursive lambdas (requires std::function, C++11βC++22)
Before C++23's std::move_only_function or deducing-this lambdas (C++23), recursive lambdas needed std::function to name their own type:
// C++11βC++20: std::function enables self-reference
std::function<int(int)> fib = [&fib](int n) -> int {
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
};
// C++23: deducing-this lambda β no std::function needed, no overhead
auto fib23 = [](this auto& self, int n) -> int {
return n <= 1 ? n : self(n - 1) + self(n - 2);
};The std::function recursive approach has measurable overhead per call due to indirection; the C++23 form inlines like a regular template.
Checking and introspecting the target
std::function<void()> f = []{ };
f.target_type(); // returns std::type_info for the stored callable
f.target<decltype([]{ })>(); // returns pointer to stored callable, or nullptr
// Equality is NOT supported
// f == g; // compile error β operator== is deletedBest Practices
Use std::function only when you need type erasure. If the callable type is statically known, a template parameter is strictly better: it inlines, it has no allocation, and it supports constexpr.
// Prefer this for hot paths and compile-time-known callables
template<std::invocable<int> F> // C++20 concept
void process(F&& fn, int x) { fn(x); }
// Use std::function when you need to store the callback across calls,
// return it from a non-template function, or put it in a container
std::function<void(int)> stored_callback;Prefer std::move_only_function (C++23) when the callable is non-copyable. std::function requires its stored callable to be CopyConstructible, which excludes lambdas that capture std::unique_ptr or other move-only types.
// C++11βC++20: forced workaround with shared_ptr
auto resource = std::make_shared<Resource>();
std::function<void()> f = [resource]{ resource->use(); }; // shared ownership
// C++23: std::move_only_function β accepts move-only captures
auto res = std::make_unique<Resource>();
std::move_only_function<void()> f = [r = std::move(res)]{ r->use(); };Avoid std::function in tight loops. Profile first, but each call incurs an indirect branch and potential cache miss. For callbacks invoked millions of times per second, the aggregate cost is significant.
Common Pitfalls
Dangling references in captures
std::function copies (or heap-allocates) its callable, but does not extend the lifetimes of objects captured by reference.
std::function<void()> make_callback() {
int local = 42;
return [&local]{ std::println("{}", local); }; // UB: local destroyed on return
}Capture by value, or ensure the captured object outlives the std::function.
Storing this in long-lived callbacks
struct Widget {
std::function<void()> on_resize;
void register_with(EventSystem& ev) {
on_resize = [this]{ reflow(); }; // raw this β no lifetime tracking
ev.subscribe(on_resize); // if Widget is destroyed first: UB
}
};Use std::weak_ptr<Widget> via shared_from_this() (C++11) if Widget lifetime is managed externally.
std::function is not noexcept callable
operator() throws std::bad_function_call if the wrapper is empty. This prevents its use in noexcept contexts and means calling an unguarded empty wrapper terminates the program via std::terminate in contexts where exceptions are disabled.
std::function<void()> f; // empty
f(); // throws std::bad_function_callOverhead from SBO misses
Lambdas with large capture lists (above ~16β32 bytes, implementation-defined) defeat the small buffer optimization and trigger heap allocation on every construction or copy of the std::function.
// This capture list may exceed SBO threshold (implementation-specific)
std::string a, b, c, d, e;
std::function<void()> f = [a, b, c, d, e]{ /* ... */ }; // likely heap-allocatesstd::function and std::bind interaction (C++11)
std::bind (C++11) produces a callable that itself stores copies of bound arguments. Wrapping it in std::function introduces a second layer of type erasure. Prefer lambdas:
// Avoid
auto f = std::function<int(int)>( std::bind(std::plus<int>{}, std::placeholders::_1, 5) );
// Prefer
auto f = std::function<int(int)>( [](int n){ return n + 5; } );See Also
std::move_only_function(C++23) β non-copyable callable wrapper, lower overheadstd::function_ref(C++26) β non-owning reference to a callable, no allocationstd::bind/std::placeholders(C++11) β partial application, largely superseded by lambdasstd::invoke(C++17) β uniform callable invocation including member pointersstd::invocable/std::regular_invocableconcepts (C++20) β constrain templates on callable types- Deducing-this lambdas (C++23) β self-referential lambdas without
std::function