Functions
std::function
Type-erased callable wrapper for functions, lambdas, and functors
Interview: Modern C++ callbacks — essential for event systems, command patterns, and functional programming idioms
std::function
std::function (C++11, <functional>) is a general-purpose, type-erased callable wrapper. It can store and invoke any callable that matches a given signature — free functions, lambdas, member functions (via std::bind or lambdas), and function objects. This flexibility makes it the standard solution for storing callbacks and building event systems.
Type Erasure and Overhead
Type erasure is the mechanism that allows std::function to store heterogeneous callables behind a uniform interface. Internally it uses virtual dispatch (or an equivalent mechanism). Small callable objects (fitting in ~16–32 bytes) use an internal small buffer optimization (SBO) to avoid heap allocation; larger ones trigger a heap allocation. This makes std::function significantly heavier than a raw function pointer.
std::bind and Partial Application
std::bind creates a callable that pre-fills some arguments of a function, producing a new callable with fewer parameters. In modern C++, lambdas with captures are almost always clearer and more efficient than std::bind — prefer lambdas.
When to Use std::function vs Templates
Use templates (template<typename F> void apply(F f)) when the callable is only used locally within a function — zero overhead, fully inlinable. Use std::function when you need to store the callable in a member variable, container, or across ABI boundaries — the type erasure is the whole point.
Interview Corner
Q: What is the performance cost of std::function vs a raw function pointer or a template parameter?
A: Raw function pointers: single indirect call (~1-2ns, one cache miss if target not predicted). Template parameter: fully inlined, zero overhead. std::function: virtual-dispatch-like indirection (~5-10ns), potential heap allocation for large callables, no inlining. For hot paths (called millions of times per second), templates win. For flexible APIs or stored callbacks, std::function's cost is usually acceptable.
Q: Why should you prefer lambdas over std::bind in modern C++?
A: Lambdas are clearer (explicit captures vs placeholder syntax), inline better (compiler understands them directly), support moves in captures (C++14: [x = std::move(x)]), and avoid the argument deduction ambiguities that std::bind suffers with overloaded functions. std::bind was the C++11 workaround before generic lambdas arrived in C++14.
Common Pitfalls
- Calling an empty std::function: Calling a default-constructed or reset
std::functionthrowsstd::bad_function_call. Always check withif (f)before calling. - Dangling reference captures: Storing a
std::functionthat holds a lambda capturing references to local variables — if the lambda outlives those variables, you have a dangling reference. - Overusing for performance-sensitive code: Using
std::functionin tight loops prevents inlining and adds indirection. Benchmark before committing to this pattern in hot paths.
Best Practices
- Use
std::functionwhen you need to store a callback (in a class member or container). Use templates when only passing a callable locally. - Check
if (callback)before invoking storedstd::functionmembers to avoidstd::bad_function_call. - Prefer lambdas over
std::bind— they are clearer, faster, and supported everywhere.