5.2.18 · Coding › C++ Programming
Intuition Ek-sentence idea
Ek concept ek named, compile-time predicate on types hota hai jo aap template se attach karte ho taaki compiler check kare "kya ye type un operations ko support karta hai jo main use karne wala hoon?" template ka body compile karne se pehle — ek 200-line template error ko ek simple "constraint not satisfied" message mein badal deta hai.
Intuition Woh pain jo yeh solve karte hain
C++20 se pehle, templates duck-typed the: template<typename T> T add(T a, T b){ return a+b; } tab tak theek compile hota tha jab tak aap isse kisi aisi type ke saath instantiate nahi karte jiske paas operator+ nahi hai. Tab error template ke andar gehrai mein phat'ti thi, aksar kisi aisi line ko point karte hue jo aapne likhi hi nahi.
WHY: templates koi bhi type accept karte hain, lekin body sirf kuch types ke liye kaam karti hai. Requirement ko pehle se state karne ka koi tarika nahi tha. Concepts aapko requirement ko code ke roop mein likhne dete hain, isliye:
Errors call site pe point karti hain ("std::string satisfied nahi kiya Numeric"), andar ki guts par nahi.
Aap requirements par overload kar sakte ho (integral vs floating types ke liye alag function choose karo).
Requirement self-documenting ban jaati hai.
Ek concept ek constexpr bool template hai jo given template arguments ke liye true ya false evaluate karta hai. Syntax:
template < typename T >
concept Numeric = std ::integral < T > || std ::floating_point < T > ;
Yahan Numeric<int> true hai, Numeric<std::string> false hai. Yeh ek compile-time predicate hai, runtime par kabhi nahi chalta.
Ek constraint kisi concept (ya boolean expression) ka use hai ek template ko restrict karne ke liye. Jis template ki constraints satisfy nahi hoti woh candidate set se remove ho jaata hai — error nahi hoti, bas consider nahi hota (isse overload resolution power milta hai).
T ko Numeric constrain karne ke chaar tarike
// 1. Abbreviated function template (shortest)
auto sq ( Numeric auto x ) { return x * x; }
// 2. Constrained template parameter
template < Numeric T >
T sq ( T x ) { return x * x; }
// 3. requires-clause after the template head
template < typename T > requires Numeric <T >
T sq ( T x ) { return x * x; }
// 4. trailing requires-clause
template < typename T >
T sq ( T x ) requires Numeric < T > { return x * x; }
Chaar kyun? Yeh alag-alag ergonomics cover karte hain: (1) quick one-liners ke liye, (3)/(4) jab condition ek complex boolean expression ho jo ek single named concept na ho.
Do alag requires hote hain. Inhe confuse mat karo.
requires
requires-clause — ek constraint introduce karta hai: requires Numeric<T>. Ek bool evaluate karta hai.
requires-expression — valid expressions list karke ek bool banata hai: requires(T a){ a + a; }. true return karta hai agar har listed expression compile ho jaaye.
Worked example Haath se ek concept derive karna
Suppose karo hum chahte hain "types jinhe + kar sako aur result bhi T ho":
template < typename T >
concept Addable = requires (T a, T b) {
{ a + b } -> std ::same_as < T > ; // a+b compile bhi ho AND type T bhi ho
};
Yeh step kyun?
requires(T a, T b) test karne ke liye kalpnik variables declare karta hai (yeh actually kabhi create nahi hote).
{ a + b } ek compound requirement hai: expression valid hona chahiye.
-> std::same_as<T> a + b ki type ko constrain karta hai.
{ } ke andar chaar requirement kinds:
Kind
Example
Matlab
simple
a + b;
expression valid hai
type
typename T::value_type;
nested type exist karta hai
compound
{ *p } -> std::convertible_to<int>;
valid aur type constraint
nested
requires Numeric<T>;
doosra constraint hold karta hai
Worked example Best-matching overload choose karo
template < std :: integral T > // (A)
void describe ( T ) { /* "integer" */ }
template < std :: floating_point T > // (B)
void describe ( T ) { /* "real number" */ }
describe ( 5 ); // (A) call karta hai: int sirf integral satisfy karta hai
describe ( 3.14 ); // (B) call karta hai: double sirf floating_point satisfy karta hai
Yeh kyun kaam karta hai: describe(5) ke liye, overload (B) ki constraint floating_point<int> false hai, isliye (B) candidates se silently remove ho jaata hai — koi error nahi, bas choose nahi hota.
Intuition Subsumption (more-constrained wins)
Agar do overloads dono apply hote hain, compiler zyada constrained wale ko prefer karta hai. SignedIntegral Integral ko subsume karta hai kyunki woh strictly zyada require karta hai, isliye agar koi candidate dono satisfy karta hai, toh zyada specific choose hota hai. Isi tarah concepts aapko enable_if ke gymnastics ke bina ordered specialization dete hain.
requires expression woh value return karta hai jo main andar compute karta hoon."
Kyun sahi lagta hai: { a + b } lagta hai a+b evaluate ho raha hai. Fix: ek requires-expression runtime par kuch bhi evaluate nahi karta — sirf poochta hai "kya yeh compile hota hai?" aur true/false yield karta hai. Braces validity test karte hain, result nahi.
requires Numeric<T> body likhta hoon aur compiler meri check run karta hai."
Kyun sahi lagta hai: Yeh if ki tarah padhta hai. Fix: concept ki body ek constexpr bool hona chahiye. concept C = Numeric<T>; theek hai; concept C = if(...){} nahi hai. Ek concept ek predicate ki definition hai, koi statement block nahi.
Common mistake Yeh bhool jaana ki removed overload
koi error nahi hai .
Kyun sahi lagta hai: aap expect karte ho ki "no match" loudly fail hoga. Fix: ek unsatisfied constraint sirf candidate ko remove karta hai. Error tabhi aati hai jab zero candidates bach jaayein ("no matching function call") — jo ki exactly wahi clean message hai jo hum chahte the.
requires requires use karna aur panic karna.
Kyun sahi lagta hai: double keyword typo jaisa lagta hai. Fix: yeh legal hai: pehla requires = clause, doosra requires = expression. template<class T> requires requires(T a){ a.size(); } void f(T);. Isse avoid karne ke liye concept ko naam do.
C++20 concept kya hota hai, ek phrase mein? Template parameters par ek named compile-time boolean predicate (ek constexpr bool template) jo templates ko constrain karne ke liye use hota hai.
Requires-clause aur requires-expression mein kya farq hai? Clause ek constraint introduce karta hai aur ek bool evaluate karta hai (requires Numeric<T>); expression expressions list karke ek bool banata hai jo compile hone chahiye (requires(T a){ a+a; }).
{ a + b } -> std::same_as<T> kya check karta hai?Ek compound requirement: a+b ek valid expression hona chahiye AUR uska type exactly T hona chahiye.
Jab do constrained overloads dono apply hote hain, kaun choose hota hai? Zyada constrained wala (subsumption) — strictly stronger requirements jeet jaati hain.
Jab template ki constraint satisfy nahi hoti tab kya hota hai? Template silently candidate set se remove ho jaata hai (error nahi hoti) jab tak koi candidate na bache.
Ek requires-expression ke andar chaar requirement kinds ke naam batao. simple, type (typename T::x), compound ({e}->C), nested (requires C<T>).
Kya requires-expression runtime par code run karta hai? Nahi — yeh sirf compile time par check karta hai ki har listed expression well-formed hai ya nahi.
Parameter x ko Numeric constrain karne ka shortest syntax batao. auto f(Numeric auto x) — abbreviated function template.
Recall Feynman: ek 12-saal ke bachche ko samjhao
Ek khilona machine imagine karo jo sirf batteries se chalta hai. Purana C++ aapko kuch bhi daalne deta tha — kela, patthar — aur sirf phat'ta tha jab andar battery use karne ki koshish karta tha, ek confusing mess ke saath. Ek concept ek sticker hai slot par jo kehta hai "sirf batteries ." Ab agar aap kela laao, machine politely kehti hai "nahi, is slot ko battery chahiye" bilkul darwaze par. Same idea: ek concept check karta hai "kya yeh type woh kar sakti hai jo mujhe chahiye?" kuch bhi tootne se pehle .
Mnemonic Do requires yaad karo
"Clause Constrains, Expression Examines."
Requires-c lause template ko c onstrain karta hai; requires-e xpression e xamine karta hai ki expressions compile hoti hain ya nahi.
Recall Quick self-test (answers chhupao!)
describe(5) error kyun nahi deta jabki ek floating_point overload exist karta hai?
Yeh sochne mein kya galat hai ki { a+b } sum return karta hai?
int ke liye Integral T aur SignedIntegral T mein kaun sa overload jeetega?
Templates — function & class templates
SFINAE and std::enable_if (purana, painful tarika jo concepts replace karta hai)
type_traits — std::integral, std::floating_point
Overload Resolution & Subsumption
constexpr — compile-time evaluation
Ranges library (C++20) (heavily built on concepts)
auto and decltype
Pre-C++20 duck-typed templates
Deep cryptic template errors
Concept: named compile-time predicate
Constraint restricts template
Removed from candidate set
requires-clause returns bool
requires-expression lists valid exprs
Every listed expression compiles