5.2.23 · Coding › C++ Programming
C++ mein ek function normally sirf ek naam hota hai jise aap seedha call karte ho. Lekin kabhi kabhi aap chahte ho ki ek callable ko ek variable mein store karo , usse pass karo, baad mein badlo, ya "karne wali cheezein" ki ek list rakho. std::function ek type-erased wrapper hai jo kisi bhi callable (free function, lambda, functor, member function pointer) ko hold kar sakta hai — jab tak call signature match kare. std::bind ek aisa tool hai jo ek callable ke kuch arguments pehle se fill kar deta hai , ek naya callable produce karta hai jiske paas kam (ya reorder kiye hue) arguments hote hain — isse partial application kehte hain.
Definition Problem kya hai
C++ mein kaafi tarah ke callables hote hain, aur unke alag alag types hote hain:
Ek free function int(int,int) ka type hota hai int(*)(int,int).
Har lambda ka apna unique unnamed type hota hai.
Ek functor ek class hoti hai jisme operator() hota hai.
Ek member function ko call karne ke liye ek object chahiye hota hai.
Aap in alag alag types ko ek container ya ek variable mein nahi daal sakte. std::function<R(Args...)> inhe sabko ek uniform type deta hai jo sirf signature R(Args...) par based hoti hai.
Intuition Type erasure ek line mein
"Mujhe parwah nahi tum kya ho ; mujhe sirf ye parwah hai ki main tumhe f(a,b) ki tarah call kar sakun aur ek R wapas milun." Yahi promise signature hai. std::function baaki sab kuch erase kar deta hai.
std::function<R(Args...)> ek class template hai jo kisi bhi aisi callable ko store, copy, aur invoke karta hai jiska call signature R(Args...) ke compatible ho. Ek empty std::function kuch nahi call karta; use invoke karne par std::bad_function_call throw hota hai.
Worked example Char alag alag callables ko EK type mein store karna
#include <functional>
#include <iostream>
int add ( int a , int b ) { return a + b; } // free function
struct Mul { int operator () ( int a , int b ) const { return a * b; } }; // functor
int main () {
std ::function <int ( int , int ) > f; // empty
f = add; // Kyun? signature int(int,int) match karta hai
std ::cout << f ( 2 , 3 ) << " \n " ; // 5
f = []( int a , int b ){ return a - b; }; // Kyun? lambda ka bhi same signature hai
std ::cout << f ( 2 , 3 ) << " \n " ; // -1
f = Mul{}; // Kyun? functor ka operator() match karta hai
std ::cout << f ( 2 , 3 ) << " \n " ; // 6
}
Ye kyun kaam karta hai: teeno int(int,int) ki tarah callable hain. std::function sirf call ka shape check karta hai, underlying type nahi.
Worked example Callbacks ki ek vector (killer use-case)
std ::vector < std ::function <void () >> tasks;
tasks. push_back ([]{ std ::cout << "save \n " ; });
tasks. push_back ([]{ std ::cout << "log \n " ; });
for ( auto& t : tasks) t (); // har task run karo
Ye step kyun? Aap lambdas ka seedha vector nahi bana sakte kyunki har lambda ek alag type ka hota hai. std::function<void()> unhe unite karta hai.
std::bind(callable, a1, a2, ...) ek naya callable produce karta hai jisme aap kuch arguments abhi fix kar dete ho aur baaki ko placeholders (std::placeholders::_1, _2, ...) ke roop mein chhorte ho jo baad mein supply kiye jayenge.
Intuition BIND actually kya karta hai (partial application)
Maan lo tumhare paas f ( x , y ) hai. x = 10 bind karne se ek naya function milta hai g ( y ) = f ( 10 , y ) . Tumne ek ko yaad rakh ke inputs ki taadaad kam kar di . Placeholders tumhe baaki inputs ko rakhne, chhodne, ya reorder karne dete hain.
Jab aap baad mein bound object ko arguments ( c 1 , c 2 , … ) ke saath call karte ho:
Bind expression mein ek fixed value as-is use hoti hai.
Ek placeholder _n ko n-th call argument c n se replace kiya jaata hai.
Worked example Ek argument fix karna
using namespace std :: placeholders ;
int sub ( int a , int b ){ return a - b; }
auto sub10 = std :: bind (sub, 10 , _1); // a=10 fixed, b=_1
sub10 ( 3 ); // -> sub(10,3) = 7
Kyun? 10 a fill karta hai; _1 kehta hai "pehla call arg b mein daalo". Toh sub10(3) ban jaata hai sub(10,3).
Worked example Arguments reorder karna
auto flip = std :: bind (sub, _2, _1); // order swap karo
flip ( 3 , 10 ); // -> sub(10,3) = 7
Kyun? _2 2nd call arg hai (10) → a mein jaata hai. _1 pehla hai (3) → b mein jaata hai. Toh hum call karte hain sub(10,3).
Worked example Ek member function bind karna
struct Counter {
int base;
int addBase ( int x ) const { return base + x; }
};
Counter c{ 100 };
auto f = std :: bind ( & Counter ::addBase, & c, _1); // object ko 1st arg ki tarah pass karo
f ( 5 ); // -> c.addBase(5) = 105
Ye step kyun? Ek member function secretly this ko apna pehla parameter leta hai. Toh bind object (ya pointer) ko pehla bound argument maanta hai.
Intuition 80/20: tumhe actually kya chahiye
Real code ka 95% std::bind ki jagah lambdas use karta hai — ye zyada clear aur fast hote hain. std::function abhi bhi unknown concrete type ke callbacks store karne ke liye zaroori hai. std::function achhe se seekho; std::bind itna seekho ki purana code padh sako.
Worked example Same cheez, dono tarike se
auto a = std :: bind (sub, 10 , _1); // purana style
auto b = []( int y ){ return sub ( 10 ,y); }; // modern, zyada clear
Common mistake "std::function free hai / function pointer ki tarah zero-cost hai."
Kyun sahi lagta hai: ye ek thin wrapper lagta hai. Reality: ye bade callables store karne ke liye heap-allocate kar sakta hai aur inhe invoke karne ke liye virtual call / indirect call use karta hai — ye inline nahi ho sakta. Fix: hot loops ke liye templates prefer karo (template<class F> void run(F f)) ya auto; std::function tabhi use karo jab tumhe sach mein ek stored uniform type chahiye.
Common mistake "_1 pehli bound value ko indicate karta hai."
Kyun sahi lagta hai: "1 = list mein pehli cheez." Reality: _1 baad ki call ka pehla argument hai, bind list mein position nahi. Fix: _n ko padhte waqt socho "woh argument jo user bound object call karte waqt n-th position par pass karta hai."
Common mistake "bind by default references capture karta hai."
Kyun sahi lagta hai: lambdas reference se capture kar sakte hain, toh log assume karte hain bind bhi karta hai. Reality: std::bind apne arguments value se copy karta hai. Reference pass karne ke liye std::ref(x) (ya std::cref) se wrap karna padega. Fix: std::bind(f, std::ref(obj), _1).
Common mistake "Empty std::function call karna theek hai, 0 return karta hai."
Reality: empty std::function invoke karne par std::bad_function_call throw hota hai. Fix: check karo if (f) f();.
Recall Feynman: 12 saal ke bacche ko explain karo
Ek TV remote (std::function) socho. Uske buttons ek fixed shape ke hain (signature). Tumhe parwah nahi ki remote Sony se baat karta hai ya Samsung se — button dabaate ho toh kaam hota hai. std::function ek aisa remote hai jo kisi bhi "TV" (function, lambda, etc.) ki taraf point kiya ja sakta hai jo same buttons samajhta ho.
Ab std::bind ek button pehle se set karne jaisa hai: tumhare paas ek volume button hai jo "kaunsa TV" aur "kitna loud" leta hai. Tum uspe ek label chipaate ho "hamesha living-room TV" ka, toh ab button sirf "kitna loud?" puchta hai. Tumne jawaab ka ek hissa pehle se yaad kar liya.
"FUNCTION = uniform remote; BIND = pre-pressed button."
Placeholders ke liye: "_n = woh n-th arg jo caller baad mein dega."
std::function<R(Args...)> kya store karta hai? Koi bhi callable (free fn, lambda, functor, member fn) jiska call signature R(Args...) se match kare, type erasure ke zariye.
Aap do alag lambdas ko seedha same variable mein kyun nahi daal sakte? Har lambda ka apna unique unnamed type hota hai; std::function unhe ek signature-based type ke under unify karta hai.
Empty std::function call karne par kya hota hai? Ye std::bad_function_call throw karta hai.
std::bind conceptually kya karta hai? Partial application: kuch arguments abhi fix karta hai, baaki ke liye placeholders chhodta hai, ek naya callable produce karta hai.
Placeholder _2 ka matlab kya hai? Bound object baad mein call karte waqt supply kiya gaya doosra argument (bind list mein 2nd item nahi).
std::bind ko argument by reference kaise pass karte ho? Use std::ref(x) (ya std::cref(x)) mein wrap karo; warna bind value se copy karta hai.
Object c ka member function addBase kaise bind karein? std::bind(&Counter::addBase, &c, _1) — object/pointer pehla bound argument hota hai (implicit this).
std::function zero-cost kyun nahi hai? Ye heap-allocate kar sakta hai aur indirect/virtual call use karta hai, isliye direct call ki tarah inline nahi ho sakta.
Modern preference: bind ya lambda? Lambda — zyada clear aur usually faster; bind zyaadatar legacy code mein milta hai.
Woh bind expression do jo sub(a,b) ke args swap kare. std::bind(sub, _2, _1).
Lambda Expressions — zyaadatar std::bind uses ka modern replacement
Function Pointers — low-level callable jo std::function wrap kar sakta hai
Functors and operator() — class-based callables
Templates and Type Erasure — std::function ke peeche ka mechanism
Callbacks and Event Systems — std::function ka primary real-world use
std::ref and std::cref — bind ke zariye references pass karne ke liye zaroori
Empty throws bad_function_call
std::bind partial application