Skip to content
C++
Library
since C++11
Intermediate

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++11

A 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::function is 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

cpp
#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

cpp
#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++23

Wrapping member functions

Member functions cannot be assigned directly to std::function<R(Args...)> without explicitly accounting for the implicit this parameter. Two patterns:

cpp
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 lifetime

Strategy pattern via struct member

cpp
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:

cpp
// 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

cpp
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 deleted

Best 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.

cpp
// 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.

cpp
// 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

cpp
#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 design

The 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).

cpp
#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; };  // OK

std::move_only_function also supports ref-qualifiers (&, &&) and noexcept in the signature, giving complete control over how operator() is declared.

Async task queues

cpp
#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.14159

std::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:

cpp
#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

cpp
#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. A function_ref always 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 a function_ref to a temporary callable object and creating a dangling reference.
  • Supports const and noexcept qualifiers 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 β€” a BoundEntityType (a trivially copyable type that can hold either a pointer to object or a pointer to function).
  • thunk-ptr β€” a function pointer of type R(*)(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:

cpp
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 behaviour

Rule: use function_ref only as a parameter type, not as a struct member or return value.

const in the signature

cpp
// 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-callable

Three-Way Comparison

std::functionstd::move_only_functionstd::function_ref
StandardC++11C++23C++26
Header<functional><functional><functional>
CopyableYesNoYes (trivially)
AllocatesYes (SBO threshold)Yes (SBO threshold)Never
Owns callableYesYesNo (borrows)
Nullable / empty stateYes (operator bool)Yes (operator bool)No (always valid)
const-correctNo (ABI defect)YesYes
Calling overheadIndirect callIndirect callIndirect call
Pass in registersNoNoYes (two pointers)
Primary use caseStorage, heterogeneous containersAsync/unique-ownership tasksFunction 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_ptr or other move-only state? Use std::move_only_function (C++23).
  • Storing a callable that must be copyable (e.g., in a std::vector alongside copies)? Use std::function (C++11) or std::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.

cpp
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

cpp
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.

cpp
std::function<void()> f;    // empty
f();                         // throws std::bad_function_call

Overhead 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.

cpp
// 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-allocates

std::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:

cpp
// 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 overhead
  • std::function_ref (C++26) β€” non-owning reference to a callable, no allocation
  • std::bind / std::placeholders (C++11) β€” partial application, largely superseded by lambdas
  • std::invoke (C++17) β€” uniform callable invocation including member pointers
  • std::invocable / std::regular_invocable concepts (C++20) β€” constrain templates on callable types
  • Deducing-this lambdas (C++23) β€” self-referential lambdas without std::function