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.
std::move_only_function (C++23)
std::move_only_function<R(Args...)> is a type-erasing callable wrapper that drops the copyability requirement imposed by std::function. The stored callable must be constructible but need not be copy-constructible, which makes it the right tool whenever the callable captures a move-only resource.
Accepting move-only captures
#include <functional>
#include <future>
#include <memory>
struct Resource { void use() {} };
// std::function cannot hold a lambda capturing unique_ptr
// auto res = std::make_unique<Resource>();
// std::function<void()> f = [r = std::move(res)]{ r->use(); }; // ERROR
// std::move_only_function handles it correctly
auto res = std::make_unique<Resource>();
std::move_only_function<void()> f = [r = std::move(res)]{ r->use(); };
f(); // OK
// f2 = f; // ERROR β not copyable by designThe const qualifier in the signature
std::move_only_function (and std::function_ref) propagate const correctly through the signature, unlike std::function, which declares operator() const but can still call a non-const underlying callable (a known defect baked into its ABI).
#include <functional>
struct Counter {
int n = 0;
void operator()() { ++n; } // non-const
};
// std::function<void()> const f = Counter{};
// f(); // compiles, but silently mutates Counter β const-correctness defect
// move_only_function<void()>: operator() is non-const, honest about mutation
std::move_only_function<void()> g = Counter{};
g(); // OK, non-const call
// move_only_function<void() const>: requires stored callable's operator() to be const
// std::move_only_function<void() const> h = Counter{}; // ERROR β operator() not const
std::move_only_function<void() const> h = []{ return 42; }; // OKstd::move_only_function also supports ref-qualifiers (&, &&) and noexcept in the signature, giving complete control over how operator() is declared.
Async task queues
#include <functional>
#include <future>
#include <queue>
// A task queue that owns move-only work items
std::queue<std::move_only_function<void()>> task_queue;
// Package a future-bearing task β packaged_task is move-only
std::packaged_task<double()> pt([]{ return 3.14159; });
std::future<double> fut = pt.get_future();
task_queue.push([task = std::move(pt)]() mutable { task(); });
task_queue.front()(); // execute
// fut.get() == 3.14159std::function_ref (C++26) β Non-Owning Callable Reference
std::function_ref<R(Args...)> is a non-owning, non-allocating reference to any callable. It is to callables what std::string_view is to strings: a lightweight handle that borrows from the original object without copying or allocating.
It is defined in <functional> and standardised in C++26 via proposal P0792R14.
When to use it
Use function_ref for function parameters where you need to accept any callable but do not need to store it past the call. This is the most common case for higher-order functions:
#include <functional>
#include <optional>
using Payload = std::optional<int>;
// Function pointer: too restrictive β no lambdas with captures
// Payload retry(size_t times, Payload(*action)());
// Template: zero overhead but forces the definition into a header
// template<class F> Payload retry(size_t times, F&& action);
// std::function: allocates, copies/moves the callable unnecessarily
// Payload retry(size_t times, std::function<Payload()> action);
// function_ref: non-owning, no allocation, can be defined in a .cpp file
Payload retry(size_t times, std::function_ref<Payload()> action);Syntax and basic use
#include <functional>
void apply(std::function_ref<int(int)> fn, int x) {
std::println("{}", fn(x));
}
// All of these work β function_ref accepts any matching callable
apply([](int n){ return n * 2; }, 5); // lambda
int triple(int n) { return n * 3; }
apply(triple, 5); // free function
struct Scale {
int factor;
int operator()(int n) const { return n * factor; }
};
Scale s{4};
apply(s, 5); // functor (lvalue β must outlive apply())Key properties (from cppreference and P0792R14)
- No default constructor, no
operator bool, no null state. Afunction_refalways refers to a valid callable. This is safe: there is nothing to check before calling. - Trivially copyable. Every specialisation is
TriviallyCopyable, so the compiler can pass it in registers under calling conventions that support two-word trivial types. - Assignment from non-callable types is deleted (
template<class T> operator=(T) = delete). This prevents accidentally binding afunction_refto a temporary callable object and creating a dangling reference. - Supports
constandnoexceptqualifiers in the signature (function_ref<R(Args...) const>,function_ref<R(Args...) noexcept>), but not ref-qualifiers.
Implementation detail: two pointers
Internally, function_ref stores exactly two members (as specified by the standard in exposition-only terms):
bound-entityβ aBoundEntityType(a trivially copyable type that can hold either a pointer to object or a pointer to function).thunk-ptrβ a function pointer of typeR(*)(BoundEntityType, Args&&...) noexcept(noex)that performs the actual dispatch.
This is the minimum possible representation: two machine words, passable in registers, zero allocation.
The lifetime rule β the callable must outlive the function_ref
Because function_ref does not own the callable, the callable must remain alive for the entire duration of the function_ref's use. This is safe by default when using function_ref only as a function parameter (the caller holds the callable on the stack), but dangerous if you store it:
std::function_ref<void()> make_ref() {
auto fn = []{ };
return std::function_ref<void()>{fn}; // DANGER: fn destroyed on return
}
// Calling the returned function_ref is undefined behaviourRule: use function_ref only as a parameter type, not as a struct member or return value.
const in the signature
// function_ref<void() const>: requires the callable to be const-invocable
// Useful when the function_ref is stored in a const context or passed to a
// function that guarantees it won't mutate state.
void invoke_const(std::function_ref<int() const> fn) {
std::println("{}", fn());
}
invoke_const([]{ return 42; }); // OK β captureless lambda is const-callableThree-Way Comparison
std::function | std::move_only_function | std::function_ref | |
|---|---|---|---|
| Standard | C++11 | C++23 | C++26 |
| Header | <functional> | <functional> | <functional> |
| Copyable | Yes | No | Yes (trivially) |
| Allocates | Yes (SBO threshold) | Yes (SBO threshold) | Never |
| Owns callable | Yes | Yes | No (borrows) |
| Nullable / empty state | Yes (operator bool) | Yes (operator bool) | No (always valid) |
| const-correct | No (ABI defect) | Yes | Yes |
| Calling overhead | Indirect call | Indirect call | Indirect call |
| Pass in registers | No | No | Yes (two pointers) |
| Primary use case | Storage, heterogeneous containers | Async/unique-ownership tasks | Function parameters |
Quick decision guide:
- Passing a callable into a function you call immediately? Use
std::function_ref(C++26). - Storing a callable that captures
unique_ptror other move-only state? Usestd::move_only_function(C++23). - Storing a callable that must be copyable (e.g., in a
std::vectoralongside copies)? Usestd::function(C++11) orstd::copyable_function(C++26).
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