5.2.17 · D5 · HinglishC++ Programming

Question bankSFINAE — substitution failure is not an error

2,048 words9 min read↑ Read in English

5.2.17 · D5 · Coding › C++ Programming › SFINAE — substitution failure is not an error

Machinery ke liye, SFINAE — substitution failure is not an error khula rakho, saath mein Templates and Type Deduction aur decltype and Trailing Return Types bhi.


Pehle, teen ideas jinpe questions tike hain

Bank se pehle, hum wo teen terms build karte hain jo har trap use karta hai, bilkul zero se.

Declaration ko ek ghar ki tarah socho: signature ek front door sign hai (enter karne se pehle check hota hai), body interior hai (sirf andar jaane ke baad check hota hai).


True or false — justify karo

Compiler tab error print karta hai jab bhi template substitution fail hoti hai.
False — signature mein failure silently overload set se remove ho jaati hai (yahi SFINAE ka poora point hai); sirf tab "no matching function" milta hai jab koi bhi candidate survive na kare.
Agar substitution failure function body ke andar hoti hai, toh SFINAE phir bhi bachata hai.
False — body immediate context nahi hai, isliye wahan failure ek hard error hai jo compilation rok deta hai.
std::enable_if<false, int>::type simply int hai.
False — primary template ka koi ::type nahi hota, isliye false kuch nahi deta; ::type ko naam dena woh substitution failure hai jo overload ko drop karti hai.
std::enable_if<true, R>::type R hai.
True — true ke liye partial specialization using type = R; define karti hai, isliye alias R resolve hota hai.
Do enable_if overloads ek type ke liye simultaneously valid ho sakte hain; compiler bas better wala choose kar leta hai.
False — agar dono same signature ke saath survive karein toh ambiguous call hai, ek hard error; conditions ek clean partition honi chahiye (figure s02 dekho).
Ek variadic ... fallback overload tab bhi jeetega jab ek constrained overload bhi viable ho.
False — ... conversion ladder par lowest-priority match hai (figure s03), isliye ye sirf tab jeetta hai jab har better-matching candidate SFINAE'd away ho chuka ho.
SFINAE aur if constexpr ek hi mechanism ke do naam hain.
False — SFINAE overload resolution ke dauran candidates hatata hai; if constexpr ek function body ke andar branches discard karta hai overload already choose hone ke baad.
Concepts (C++20) sirf prettier syntax hain bina kisi behavioural difference ke enable_if se.
Mostly false — ye better error messages bhi dete hain aur overloads ko subsumption ke zariye order karte hain (more-constrained wala jeetta hai, figure s04); Concepts (C++20) dekho.
decltype(t.size(), size_t{}) jo bhi t.size() return karta hai wahi return karta hai.
False — comma operator t.size() ko sirf validity ke liye evaluate karta hai aur right-hand type yield karta hai, isliye return type size_t hai, t.size() ka type nahi.
Do otherwise-identical templates ke return type mein sirf std::enable_if differences rakhna hamesha safe hai.
False — isse "redefinition"/signature-clash issues trigger ho sakte hain; robust idiom ek defaulted non-type template parameter std::enable_if_t<cond,int> = 0 hai.

Error dhundo

Ye "fail nicely" plan kyun kaam nahi karta? template<class T> void f(T t){ t.foo(); } — "agar T mein foo nahi hai, SFINAE use drop kar deta hai."
t.foo() call body mein hai (ghar ka interior, door sign nahi), immediate context mein nahi, isliye SFINAE ke liye kuch nahi hai — ye ek hard error hai. Check ko decltype(t.foo()) ya enable_if ke zariye signature mein laao.
std::enable_if_t<cond> bina kisi doosre argument ke — enabled overload ka return type kya hai?
enable_if ka default doosra parameter void hai, isliye enable_if_t<true> void hai; void-returning overload ke liye theek hai, lekin yaad raho ye default void hai.
enable_if_t<is_integral_v<T>,void> f(T); aur enable_if_t<is_integral_v<T>,void> f(T); — kya galat hai?
Dono conditions identical hain, isliye har integral T ke liye dono survive karte hain → dono regions overlap karte hain → ambiguous (aur effectively ek redefinition). Doosra !is_integral_v<T> hona chahiye space partition karne ke liye (figure s02).
auto g(const T& t) -> decltype(t.size()) getSize return karta hai — ye phir bhi hard-error kyun dे sakta hai?
Sirf t.size() (signature mein) protected hai. Agar body koi aur unchecked member use kare (jaise t.capacity()), to us member ki absence immediate context ke bahar hai → hard error, SFINAE nahi.
Ek detector body mein T::value_type use karta hai behaviour decide karne ke liye aur fallback expect karta hai. Ye kahan toot ta hai?
Body mein ye un types ke liye hard error hai jinmein value_type nahi hai; check signature / immediate context mein hona chahiye (trailing decltype, enable_if, ya void_t Detection Idiom).

Why questions

SFINAE exist kyun karta hai — iske bina hum kya khote?
Iske bina, pehla ill-formed candidate jise compiler try karta poora compile khatam kar deta; SFINAE ek failed substitution ko ek silent question banne deta hai — "kya ye type X support karta hai?" — compile-time branching enable karta hai.
Failure immediate context mein kyun honi chahiye body mein nahi?
Compiler signature mein sirf substitution karta hai (parameter list/defaults, return type, parameter types) jabki candidates select kar raha hota hai; body baad mein compile hoti hai, ek candidate already choose hone ke baad, isliye body error ke paas "doosra candidate" nahi hota fall back karne ke liye.
decltype(expr, ReturnType{}) ek common SFINAE trick kyun hai sirf decltype(expr) ke bajaye?
Comma operator tumhein expr ko validity-check karne deta hai jabki phir bhi ek chosen type (ReturnType) return karta hai, "kya ye compile hota hai?" ko "main kya return karun?" se decouple karta hai.
Overlapping enable_if conditions ek pick ke bajaye error kyun cause karti hain?
Overload resolution ko ek unique best match chahiye; do equally-good survivors genuinely ambiguous hain (figure s02 mein ek overlap region), isliye standard ise ek error banata hai arbitrary choice ke bajaye.
... parameter classic fallback kyun hai?
Conversion-ranking ladder par (figure s03) ellipsis conversion baaki sabhi conversions se neeche rank karta hai, isliye fallback sirf tab choose hota hai jab sabhi constrained overloads remove ho chuke hon — exactly "jab kuch aur fit na ho" wala role.
C++20 Concepts ne is pattern ko partly kyun replace kiya?
enable_if machinery dense hai aur iske errors cryptic hain; Concepts same constraints ko readably express karte hain, overloads ko subsumption ke zariye order karte hain (more-constrained jeetta hai, figure s04), aur report karte hain ki kaun si requirement fail hui.

Edge cases

Agar SFINAE ek call ke liye ek maatra candidate ko remove kar de toh kya hota hai?
Tumhein generic "no matching function for call" milta hai — nahi underlying "int has no value_type" error, jo debug karna confusing ho sakta hai.
Kya ek template argument deduce karne mein failure (kisi bhi substitution se pehle) SFINAE hai?
Ye same family ka "candidate not viable, aage badho" behaviour hai — ek failed deduction bhi candidate ko silently hata deta hai error ke bajaye.
Kya ek default template argument mein substitution failure SFINAE count hoti hai?
Haan — template parameter defaults immediate context ka hissa hain, isliye ek invalid default candidate ko silently drop kar deta hai.
Agar enable_if differences ek non-type template parameter default mein rakhe jaayein, toh kya do overloads alag maane jaate hain?
Ye us parameter se differ karte hain, isliye ye distinct declarations hain; mutually exclusive conditions ke saath milke, exactly ek survive karta hai — ye recommended idiom hai.
Kisi aisi type ke liye jahan ek expression sirf body ke nested requirement ke andar ill-formed hai, kya SFINAE kick in karega?
Nahi — signature ke neeche kuch bhi immediate context nahi hai; sirf jo parameter list/defaults, return type, ya parameter types mein appear ho woh SFINAE-protected hai.

Connections