Exercises — std - function and std - bind
5.2.23 · D4· Coding › C++ Programming › std - function and std - bind
Poore note mein ye assume karo:
#include <functional>
#include <iostream>
#include <vector>
using namespace std::placeholders; // gives us _1, _2, ...L1 — Recognition
Goal: pehchano ki kya kahan fit hota hai, koi tracing nahi chahiye.
Exercise 1.1 — Kaun sa signature?
Aapke paas int add(int a, int b) hai. Blank fill karo taaki yeh compile ho:
std::function<______> f = add;Recall Solution
Answer: int(int,int).
std::function ka template parameter function type ki tarah likha jaata hai, normal template arguments ki tarah nahi. add int return karta hai aur do ints leta hai, isliye iska call signature int(int,int) hai. Poori line: std::function<int(int,int)> f = add;
Exercise 1.2 — Woh callable dhundho jo fit NAHI hota
Inme se kaun std::function<double(double)> mein store ho sakta hai?
double sq(double x){ return x*x; } // A
auto lam = [](double x){ return x + 1.0; }; // B
struct Neg { double operator()(double x) const { return -x; } }; // C
int badcount(int a, int b){ return a+b; } // DRecall Solution
A, B, C fit karte hain. D nahi karta.
std::function<double(double)> kuch bhi accept karta hai jo callable ho aur ek double in, ek double out ho.
sq— exactly match karta hai.lam— ek lambda jo ekdoubleleta hai,doublereturn karta hai.Neg{}— ek functor jiskaoperator()match karta hai.badcountdoints leta hai — galat argument count, isliye isko wrap nahi kiya ja sakta.std::functioncall shape check karta hai, aur yeh shape galat hai.
L2 — Application
Goal: khud sahi expression likho.
Exercise 2.1 — Teen callables ek vector mein store karo
Aisa code likho jo in teeno tasks ko ek std::vector mein daale aur inhe order mein run kare:
- ek lambda jo
"boot"print kare, - ek lambda jo
"load"print kare, - ek free function
void shutdown()jo"halt"print kare.
Recall Solution
void shutdown(){ std::cout << "halt\n"; }
std::vector<std::function<void()>> tasks;
tasks.push_back([]{ std::cout << "boot\n"; });
tasks.push_back([]{ std::cout << "load\n"; });
tasks.push_back(shutdown);
for (auto& t : tasks) t();Output:
boot
load
halt
Kyun kaam karta hai: har lambda ka apna alag unnamed type hota hai, isliye directly lambdas ka vector banana impossible hai. std::function<void()> teeno ko ek hi type deta hai jo sirf void() signature pe based hai.
Exercise 2.2 — bind se ek argument fix karo
int power(int base, int exp) (jo base^exp compute karta hai) diya hai, std::bind use karke ek callable square banao taaki square(n), n*n return kare.
Recall Solution
int power(int base, int exp){
int r = 1;
for (int i = 0; i < exp; ++i) r *= base;
return r;
}
auto square = std::bind(power, _1, 2); // exp fixed = 2, base = _1
// square(5) -> power(5, 2) = 25Kyun: hum chahte hain ki base caller se aaye aur exponent 2 pe lock ho jaaye. Toh base placeholder _1 ban jaata hai (pehla call argument) aur exp fixed value 2 hai. square(5) expand hota hai power(5, 2) = 25 mein.
L3 — Analysis
Goal: exactly trace karo kya run hoga; bug dhundho.
Exercise 3.1 — Output predict karo (reordering)
int sub(int a, int b){ return a - b; }
auto g = std::bind(sub, _2, _1);
std::cout << g(3, 10) << "\n";Kya print hoga?

Recall Solution
7 print hoga.
_n ko padhein jaise "caller ka n-th argument". Caller (3, 10) supply karta hai, toh _1 = 3 aur _2 = 10.
- Pehla bind slot hai
_2→amein jaata hai →a = 10. - Doosra bind slot hai
_1→bmein jaata hai →b = 3.
Toh g(3,10) ban jaata hai sub(10, 3) = 7. Figure dekho: crossing arrows poora point hain — _2 aur _1 caller ke inputs ko sub tak pahunchne se pehle swap kar dete hain.
Exercise 3.2 — Copy-vs-reference bug
struct Accumulator {
int total = 0;
void add(int x){ total += x; }
};
Accumulator acc;
auto f = std::bind(&Accumulator::add, acc, _1); // note: acc, not &acc
f(5);
f(5);
std::cout << acc.total << "\n";Kya print hoga, aur yeh surprising kyun hai?
Recall Solution
0 print hoga.
std::bind apne arguments ko value se copy karta hai. acc likhna (na ki &acc) bind ko accumulator ki ek copy deta hai. f ko har call woh hidden internal copy ko mutate karta hai, asli acc ko kabhi nahi. Toh acc.total 0 rehta hai.
Do sahi fixes:
auto f = std::bind(&Accumulator::add, &acc, _1); // pointer pass karo
auto g = std::bind(&Accumulator::add, std::ref(acc), _1); // reference wrapper pass karoDono taraf se calls ab asli acc tak pahunchenge, aur 10 print hoga. (Dekho std::ref and std::cref.)
Exercise 3.3 — Empty-function crash
std::function<int(int)> f; // never assigned
std::cout << f(42) << "\n";Runtime pe kya hoga?
Recall Solution
Yeh std::bad_function_call throw karega (program terminate hoga jab tak aap isse catch na karo). Ek empty std::function mein koi target nahi hota, toh invoke karne ke liye kuch hai hi nahi.
Fix — hamesha guard karo:
if (f) std::cout << f(42) << "\n";
else std::cout << "no target\n";if (f) tab hi true hota hai jab std::function currently ek callable hold kare.
L4 — Synthesis
Goal: pieces ko ek chota working design mein combine karo.
Exercise 4.1 — Ek tiny event dispatcher
Ek class Button banao jo void() callbacks ki list (onClick) store kare, aur zyada register karne de, aur click() se sab fire kare. Phir do lambdas aur ek bound member function Logger::log register karo.
Recall Solution
struct Logger {
void log() const { std::cout << "logged\n"; }
};
struct Button {
std::vector<std::function<void()>> handlers;
void onClick(std::function<void()> h){ handlers.push_back(std::move(h)); }
void click(){ for (auto& h : handlers) h(); }
};
int main(){
Logger lg;
Button b;
b.onClick([]{ std::cout << "sound\n"; });
b.onClick([]{ std::cout << "ripple\n"; });
b.onClick(std::bind(&Logger::log, &lg)); // bound member fn
b.click();
}Output:
sound
ripple
logged
Kyun design kaam karta hai: std::function<void()> woh uniform "shape" hai jis par har handler agree karta hai. Lambdas, free functions, aur bound member functions sab us ek type mein collapse ho jaate hain, isliye woh ek hi vector mein khushi se rehte hain. Yeh bilkul Callbacks and Event Systems pattern hai. (Note karo ki &Logger::log ko ek object chahiye — yahan pointer &lg — apna first bound argument ke roop mein, kyunki member function secretly pehle this leta hai.)
Exercise 4.2 — bind + placeholders compose karke "clamp lower bound" banao
int maxOf(int a, int b){ return a>b ? a : b; } diya hai, atLeast5 banao taaki atLeast5(x) x return kare agar x >= 5 ho, warna 5.
Recall Solution
auto atLeast5 = std::bind(maxOf, _1, 5); // a = caller's x, b = 5
// atLeast5(3) -> maxOf(3,5) = 5
// atLeast5(9) -> maxOf(9,5) = 9Kyun: max(x, 5) exactly hai "kabhi 5 se neeche nahi". Caller ke argument ko a mein route karte hain (_1 se) aur floor 5 ko b mein lock karte hain. Dono orderings (_1,5 ya 5,_1) yahan same answer dete hain kyunki max symmetric hai — ek accha self-check ki aapne mapping samajh li.
L5 — Mastery
Goal: cost, alternatives, aur subtle semantics ke baare mein reason karo.
Exercise 5.1 — Cost reasoning
Aapka inner loop ek callback 10 million times call karta hai. Version A std::function<int(int)> leta hai; version B template<class F> ... F f hai. Kaun faster hai, aur kyun — ek precise sentence mein ki compiler help kyon kar/nahi kar sakta?
Recall Solution
Version B (template) faster hai.
Ek template callable ke concrete type ke saath instantiate hota hai, isliye compiler call site par exact code dekhta hai aur use inline kar sakta hai. std::function concrete type ko type erasure ke peeche chhupa deta hai (dekho Templates and Type Erasure): call ek indirect / virtual-like dispatch se jaati hai jo inline nahi ho sakti, aur bade targets ke liye isko construct karne mein heap-allocation ho sakti hai. Toh std::function ek chhota runtime cost de kar unknown types ko uniformly store karne ki ability paata hai — ise sirf tab use karo jab aapko actually woh uniformity chahiye.
Exercise 5.2 — bind vs lambda equivalence
std::bind(sub, _2, _1) (Exercise 3.1 se) ko ek modern lambda ki tarah rewrite karo, aur ek reason batao ki lambdas usually kyun prefer ki jaati hain.
Recall Solution
auto g = [](int x, int y){ return sub(y, x); }; // g(3,10) -> sub(10,3) = 7Prefer karne ka reason: lambda argument routing ko directly code mein spell out karta hai jo aap padhh sakte ho (sub(y, x)), jabki _2, _1 reader ko placeholder positions mentally decode karne par majboor karta hai. Lambdas compiler ke liye inline karna bhi aasaan hain aur std::bind ki machinery nahi kheenchte. Wide callable landscape ke liye dekho Lambda Expressions vs Function Pointers.
Exercise 5.3 — Trickiest output predict karo
int f(int a, int b, int c){ return a*100 + b*10 + c; }
auto h = std::bind(f, _3, _1, 7);
std::cout << h(2, 99, 5) << "\n";Kya print hoga? (Har slot dekho.)

Recall Solution
527 print hoga.
Caller (2, 99, 5) supply karta hai → _1 = 2, _2 = 99, _3 = 5.
f ke har parameter (a, b, c) ko uske bind slot se map karo:
a←_3→5b←_1→2c← fixed7
Toh actual call hai f(5, 2, 7) = 5*100 + 2*10 + 7 = 527.
Dhyan do ki _2 = 99 kabhi use nahi hota — placeholders aapko call arguments drop karne bhi dete hain. Figure wiring dikhata hai: teen arrows andar, lekin 99 wali wire simply dead-end ho jaati hai.
Recall Self-test summary
Placeholder _n ka matlab kya hai? ::: Woh n-th argument jo bound object baad mein call hone par supply kiya jaata hai.
std::bind se kisi object ka live link kaise rakhte ho? ::: Pointer &obj pass karo ya std::ref(obj) mein wrap karo; plain bind value se copy karta hai.
Empty std::function call karne par kya hota hai? ::: std::bad_function_call throw hota hai; if (f) se guard karo.
Template callback std::function se usually faster kyun hota hai? ::: Template concrete type rakhta hai, isliye call inline ho sakti hai; std::function type erase karta hai aur indirectly dispatch karta hai.