5.2.23 · D3 · Coding › C++ Programming › std - function and std - bind
Yeh page ek drill hai. Hum har us shape ko enumerate karte hain jis situation mein std::function aur std::bind tumhare saamne aa sakti hain, phir har shape ka ek example work karte hain. Agar tumne abhi tak wrapper idea nahi padha, toh pehle parent std::function and std::bind padho — yeh page assume karta hai ki tum jaante ho ki std::function<R(Args...)> koi bhi callable store karta hai jo signature se match kare, aur std::bind arguments pehle se fill kar deta hai.
Shuru karne se pehle, ek word jo hum baar baar use karenge: arity . Kisi callable ki arity simply kitne arguments leti hai hoti hai. sub(a,b) ki arity 2 hai. Jab hum bind karte hain, toh hum arity lower karte hain — hum kam arguments dete hain kyunki kuch pehle se yaad ho jaate hain. Yeh picture dhyan mein rakho:
Har case neeche ek cell hai. Worked examples labeled hain us cell ke saath jo wo hit karta hai, aur milke poora grid cover karte hain.
Cell
Kya stress karta hai
Callable kind
bind action
C1
Ek variable mein alag-alag callables store aur swap karo
free fn / lambda / functor
none
C2
Callbacks ka container (heterogeneous types)
lambdas
none
C3
Ek argument fix karo (arity 2 → 1)
free fn
fix + _1
C4
Arguments reorder karo (arity change nahi)
free fn
_2, _1
C5
Ek argument bilkul drop karo (arity kam, unused call arg)
free fn
fix only
C6
Member function bind karo (hidden this)
member fn
object + _1
C7
Reference semantics — copy vs std::ref
lambda over state
fix by ref
C8
Degenerate: empty std::function call karo
none
none
C9
Limiting: arity 0, aur nesting bind-in-bind
free fn
_1 reuse
C10
Exam twist — side effects ka evaluation order
free fn
_1, _1
Worked example Ek free function, ek lambda, aur ek functor ko same
std::function mein store karo, har ek ko (6, 2) se call karo.
int add ( int a , int b ){ return a + b; }
struct Mul { int operator () ( int a , int b ) const { return a * b; } };
std ::function <int ( int , int ) > f;
f = add; // (1)
f = []( int a , int b ){ return a - b;}; // (2)
f = Mul{}; // (3)
Forecast: aage padhne se pehle har assignment ke baad f(6,2) ka result guess karo.
f = add — Yeh step kyun? add ka signature int(int,int) hai, exactly wrapper ke signature jaisa, isliye accept ho jaata hai. f(6,2) = add(6,2) = 8 .
f = lambda — Kyun? Lambda ka type add se alag hai, lekin iska call shape int(int,int) phir bhi match karta hai. Assign karne se stored callable replace ho jaata hai. f(6,2) = 6-2 = 4 .
f = Mul{} — Kyun? Mul::operator() ko int(int,int) ki tarah call kar sakte hain. Ab f(6,2) = 6*2 = 12 .
Verify: teen assignments, teen answers 8, 4, 12 . Har stored value agli assignment par throw ho jaata hai (ek waqt mein sirf ek rehta hai). Units: sab plain int, koi surprise nahi.
Worked example Teen lambdas ko ek
vector mein push karo, unhe run karo, print hue characters count karo.
std ::vector < std ::function <void () >> tasks;
tasks. push_back ([]{ std ::cout << "AB" ; }); // 2 chars
tasks. push_back ([]{ std ::cout << "CDE" ; }); // 3 chars
tasks. push_back ([]{ std ::cout << "F" ; }); // 1 char
for ( auto& t : tasks) t ();
Forecast: total kitne characters, aur kya ek raw vector<lambda> yeh kar sakta hai?
Har lambda ka apna unnamed type hota hai. std::function se kyun bind karo? Ek vector ko ek element type chahiye; std::function<void()> woh ek type hai. Iske bina, teeno lambdas ek container share nahi kar sakte.
Loop har ek ko insertion order mein invoke karta hai → print hota hai AB, CDE, F.
Verify: total chars = 2 + 3 + 1 = 6 . Output string = "ABCDEF" (length 6). ✔
sub(a,b)=a-b se, sub10 banao jo hamesha a=10 use kare. sub10(3) evaluate karo.
using namespace std :: placeholders ;
auto sub10 = std :: bind (sub, 10 , _1);
sub10 ( 3 );
Forecast: answer 10 − 3 hai ya 3 − 10 ?
10 sub ke position a mein baitha hai. Yeh step kyun? Bind expression mein bare value as-is use hoti hai, us parameter slot se glued ho jaati hai. Toh a lock ho jaata hai 10 pe.
_1 position b mein baitha hai. Kyun? _1 ka matlab hai "caller baad mein jo pehla argument supply karega." Jab hum sub10(3) call karte hain, woh 3 b mein flow karta hai.
Effective call: sub(10, 3).
Verify: sub10(3) = 10 - 3 = 7 . Arity 2 se 1 pe drop ho gayi. ✔
flip banao jo sub ke args ka order swap kare. flip(3, 10) evaluate karo.
auto flip = std :: bind (sub, _2, _1);
flip ( 3 , 10 );
Forecast: 3-10 ya 10-3?
_2 a mein baitha hai. Kyun? _2 = doosra call argument = 10. Toh a = 10.
_1 b mein baitha hai. Kyun? _1 = pehla call argument = 3. Toh b = 3.
Effective call: sub(10, 3).
Verify: flip(3,10) = 10 - 3 = 7 . C3 jaisa hi answer lekin reordering se bana hai, fixing se nahi — koi argument drop nahi hua, arity 2 rahi. ✔
sub ko (20, 4) pe fully fix karo. Ek junk extra argument se call karo. Kya hoga?
auto twenty_minus_four = std :: bind (sub, 20 , 4 );
twenty_minus_four ( 999 ); // the 999 is IGNORED
Forecast: kya extra 999 error cause karega, ya gaayab ho jaayega?
Dono slots fixed values hain (20, 4); koi placeholder nahi hai. Yeh kyun matter karta hai? Koi _n nahi hone se, call arguments mein se kuch bhi sub se wire nahi hota.
Bound object ko extra call arguments jo kisi bhi placeholder se referenced nahi hain, simply discard ho jaate hain — yeh legal hai.
Effective call: sub(20, 4).
Verify: result = 20 - 4 = 16 , chahe tum kuch bhi pass karo. Bound object ki arity computation ke liye effectively 0 hai. ✔
Counter{base=100} mein int addBase(int x){ return base + x; } hai. Ise object c se bind karo aur 5 ke saath call karo.
struct Counter { int base; int addBase ( int x ) const { return base + x; } };
Counter c{ 100 };
auto f = std :: bind ( & Counter ::addBase, & c, _1);
f ( 5 );
Forecast: yahan pehla bound argument kya hai — kya woh 5 hai?
&Counter::addBase — &Class:: kyun? Member function ek plain value nahi hai; tum ise member-function pointer se name karte ho.
&c pehla bound argument hai. Kyun? Har member function secretly object ko ek hidden first parameter (this) ke roop mein receive karta hai. Bind us hidden parameter ko explicit banata hai, isliye object pehle jaata hai.
_1 x fill karta hai. f(5) call karne par 5 x mein jaata hai.
Effective call: c.addBase(5) = 100 + 5.
Verify: f(5) = 105 . addBase ki visible arity 1 hai, lekin bound arity bhi 1 hai kyunki object fix ho gaya. ✔
Worked example Ek counter
int n = 0 aur ek lambda jo referenced int increment kare. Value se bind karo, phir std::ref se, aur n observe karo.
int n = 0 ;
auto bump = []( int& r ){ r += 1 ; };
auto by_copy = std :: bind (bump, n); // BUG intent: bumps a COPY
auto by_ref = std :: bind (bump, std :: ref (n)); // bumps the real n
by_copy (); by_copy (); // n unchanged
by_ref (); by_ref (); // n = 2
Forecast: dono blocks ke baad, n kya hai?
std::bind(bump, n) n ko bound object mein copy karta hai. Kyun? std::bind apne arguments by default by value store karta hai. Toh by_copy() ek internal copy increment karta hai — real n kabhi nahi badhta.
std::bind(bump, std::ref(n)) ek reference wrapper store karta hai. std::ref kyun? Yahi ek tarika hai bind ko batane ka ki "original ka handle rakho, copy mat karo." Dekho std::ref and std::cref .
by_ref ke do calls 1 har baar add karte hain → n jaata hai 0 → 1 → 2.
Verify: final n = 2 (do by_copy() calls ne 0 contribute kiya). ✔
Common mistake "bind lambda ke
[&] ki tarah reference se capture karta hai."
Nahi — std::bind copy karta hai. Sirf std::ref/std::cref tum wapas reference semantics mein opt karta hai.
std::function jisme kabhi koi callable assign nahi hua — ise call karne par kya hoga?
std ::function <int ( int ) > f; // empty
if (f) { /* ... */ } // false
f ( 5 ); // throws!
Forecast: 0 return karta hai? Garbage return karta hai? Ya throw karta hai?
Default-constructed std::function mein kuch nahi hota. if (f) se guard kyun karo? Bool test batata hai ki koi target stored hai ya nahi.
Empty wrapper ko invoke karne par forward karne ke liye koi target nahi hota, isliye yeh std::bad_function_call throw karta hai.
Verify: exception type exactly std::bad_function_call hai; empty ke liye static_cast<bool>(f) false hota hai. Safe pattern hai if (f) f(5);. ✔
Worked example (a) Fix-ke-baad nullary function bind karo; (b)
_1 do baar reuse karo.
int nine (){ return 9 ; }
auto g = std :: bind (nine); // (a) arity 0, stays 0
int addTriple ( int a , int b , int c ){ return a + b + c; }
auto twice = std :: bind (addTriple, _1, _1, 10 ); // (b) _1 used twice
twice ( 4 );
Forecast: g() = ? aur twice(4) = ?
std::bind(nine) — Kyun zahmat karo? Yeh sirf ek zero-argument call wrap karta hai; bound object bhi zero args leta hai. Kuch fix nahi, kuch placeholder nahi. g() = 9 .
_1 kai baar appear ho sakta hai. Kyun? Placeholder ek substitution rule hai, consume-once token nahi; wahi call argument kai slots ko feed kar sakta hai.
twice(4) → addTriple(4, 4, 10).
Verify: g() = 9 . twice(4) = 4 + 4 + 10 = 18 . ✔
Worked example Ek logging function order record karta hai; bind
_1 reuse karta hai. Recorded values predict karo.
int record ( int a , int b ){ return 100 * a + b; } // encodes (a,b) as one int
auto weird = std :: bind (record, _1, _2);
weird ( 7 , 3 );
Forecast: kya _1 7 grab karta hai ya 3?
_1 → pehla call arg 7 → parameter a.
_2 → doosra call arg 3 → parameter b.
Effective call record(7, 3) returns 100*7 + 3.
Verify: weird(7,3) = 703. Encoding se hum prove kar sakte hain kis slot ko kaun si value mili : hundreds digit = a = 7, ones = b = 3. ✔
Recall Matrix ko memory se cover karo
Kaunsa cell argument drop karna test karta hai? ::: C5 — sab slots fixed, extra call args ignore ho jaate hain.
Kaunsa cell throw karta hai? ::: C8 — empty std::function call karna std::bad_function_call throw karta hai.
std::bind ke through real reference kaise rakhte hain? ::: Arg ko std::ref mein wrap karo (C7); bind by default copy karta hai.
Kya ek bind expression mein _1 do baar appear ho sakta hai? ::: Haan — yeh substitution rule hai, toh wahi call arg har _1 slot ko feed karta hai (C9b).
Mnemonic Placeholder rule, ek line mein
"_n = woh n-th arg jo caller baad mein dega — fixed values freeze hain, placeholders wires hain."
Dekho bhi: Lambda Expressions , Function Pointers , Functors and operator() , Templates and Type Erasure , Callbacks and Event Systems .