5.2.23 · D5C++ Programming
Question bank — std - function and std - bind
Prerequisites worth revisiting before you start: Lambda Expressions, Function Pointers, Functors and operator(), Templates and Type Erasure, Callbacks and Event Systems, and std::ref and std::cref.
True or false — justify
Two different lambdas can be stored in the same std::vector<std::function<void()>>.
True — each lambda has its own unique type, but
std::function<void()> erases that type so both fit the same slot, as long as their call shape is void().A std::function<int(int,int)> and a raw function pointer int(*)(int,int) have the same type.
False — the function pointer is one concrete type;
std::function is a wrapper that can hold that pointer (and lambdas, functors...) behind a uniform interface. Same call signature, different types.std::bind captures its bound arguments by reference by default.
False —
std::bind copies every bound argument by value. You must wrap with std::ref(x) / std::cref(x) (see std::ref and std::cref) to keep a reference.Calling a default-constructed std::function returns a zero/default value.
False — an empty
std::function holds no target, so invoking it throws std::bad_function_call. Guard with if (f) f();.std::function is a zero-cost abstraction, just like a function pointer.
False — it may heap-allocate for large callables and calls its target through an indirect/virtual dispatch, so the call generally cannot be inlined.
In std::bind(f, _1), the _1 refers to the first argument written in the bind expression.
False —
_1 is the first argument the caller passes later when invoking the bound object, not a position in the bind list.You can copy a std::function object freely.
True —
std::function is copyable (it copies its stored callable), which is exactly why it works in containers; but the copy may allocate.A lambda that captures state (e.g. [x](){...}) cannot be stored in std::function.
False — capturing lambdas are still callables;
std::function stores their state too. It's function pointers that can't hold captured state, not std::function.std::bind and a lambda doing the same job produce identical machine code.
False — a lambda is usually more inlinable and clearer;
bind builds a bind-expression object with its own overhead, so it is often slower and harder to optimise.Spot the error
std::function<int(int,int)> f = [](int a){ return a; }; f(1,2);
The lambda takes one argument but the signature promises two — the call shape doesn't match
int(int,int), so assignment (or the call) fails to compile.std::function<void()> f; f();
f is empty (never assigned a target), so calling it throws std::bad_function_call at runtime. Check if (f) first.auto g = std::bind(sub, _1); g(3, 10); where sub(int,int).
Only
_1 is provided for two parameters; b has nothing bound, so the bind expression is ill-formed for a two-arg function — you must supply both, e.g. std::bind(sub, _1, _2).std::bind(f, obj, _1) to keep obj as a live reference.
obj is copied by value, so mutations inside f hit the copy, not the original. Use std::bind(f, std::ref(obj), _1).std::bind(&Counter::addBase, _1); to call a member function.
A member function needs an object for its implicit
this. You must supply the object/pointer as the first bound argument: std::bind(&Counter::addBase, &c, _1).std::function<int(int,int)> f = Mul{}; where Mul::operator() is not marked const, used on a const std::function.
std::function's operator() is const, so it needs to call the stored callable in a const context; a non-const operator() functor won't be callable that way — mark operator() const.Why questions
Why can't a plain function pointer replace std::function for storing capturing lambdas?
A function pointer holds only a code address with no room for captured state; a capturing lambda carries data, which only a type-erasing wrapper like
std::function can store alongside the code.Why does std::function sometimes heap-allocate?
Small callables fit in an internal buffer (small-object optimisation), but a large captured state exceeds that buffer, so the wrapper allocates on the heap to store the target.
Why does binding a member function require passing the object as the first argument?
A non-static member function implicitly takes
this as a hidden first parameter, so bind treats the object (or its pointer) as bound argument number one.Why do experts prefer lambdas over std::bind today?
Lambdas read like ordinary code, avoid placeholder gymnastics, are easier for the compiler to inline, and don't have
bind's surprising by-value copy semantics.Why does std::function throw instead of crashing when empty?
It defines a well-specified behaviour: an empty target has nothing to invoke, so it raises
std::bad_function_call, giving you a catchable, defined error rather than undefined behaviour.Why is the template parameter written R(Args...) (a function type) instead of <R, Args...>?
It uses a real function-type signature so the shape of the call is expressed directly and naturally, matching how the callable will actually be invoked.
Why can std::function unify unrelated types like a free function and a functor?
Through type erasure — it stores a hidden interface exposing only "call me with these args, get this return", discarding the concrete type (see Templates and Type Erasure).
Edge cases
What does std::bind(sub, _2, _1) do when called as flip(3, 10)?
_2 grabs the 2nd caller arg (10) → parameter a; _1 grabs the 1st (3) → parameter b; so it calls sub(10, 3) — arguments reordered.What happens if you pass more call arguments than placeholders use, e.g. bound object uses only _1 but you call it with (3, 99)?
The extra argument (99) is simply ignored;
bind only forwards the placeholders that actually appear, so unused trailing call args are discarded.Can a single placeholder appear twice, like std::bind(f, _1, _1)?
Yes — the same caller argument is copied into both positions, so
g(5) becomes f(5, 5); placeholders may be reused freely.Is assigning a lambda to a compatible std::function a copy or a reference?
A copy —
std::function owns its target by value, so later changes to the original lambda object do not affect the stored copy.Does an empty std::function convert to false in a boolean context?
Yes —
std::function has an explicit operator bool that is false when empty and true when it holds a target, which is why if (f) f(); is the safe idiom.What is the state of a std::function after being moved-from?
It is left empty (no target), so calling it would throw
std::bad_function_call; treat a moved-from std::function as empty until reassigned.