दिलचस्प पोस्ट
क्या रूबी में सैकड़ों पाठ प्रतिस्थापन करने का एक प्रभावी तरीका है? IOS UIWebView में जावास्क्रिप्ट console.log () आप ASP.Net MVC में उपयोगकर्ता ऑब्जेक्ट का UserID कैसे प्राप्त करते हैं? आईओएस 10: " अगर हम वास्तविक प्री-कमिट हैंडलर में हैं तो हम सीए प्रतिबंध के कारण वास्तव में किसी भी नई बाड़ को नहीं जोड़ सकते हैं" onSaveInstanceState () और onRestoreInstanceState () क्या मैं अहस्ताक्षरित चार को चार में बदल सकता हूँ और इसके विपरीत? MySQL डाटाबेस का सही आकार कैसे प्राप्त करें? पायथन नॉन-लॉकल स्टेटमेंट सी ++: क्या regex पुस्तकालय मुझे इस्तेमाल करना चाहिए? आप NSUserDefaults के लिए एक पूर्णांक कैसे बचा सकते हैं? एक उच्च गुणवत्ता 1024×1024 .jpg को एक .eps फ़ाइल को कन्वर्ट करने के लिए कैसे? जावा में हर तीसरे कोमा पर स्ट्रिंग विभाजित करें iPhone / iOS JSON पार्सिंग ट्यूटोरियल जावा में एक मूल कार्यान्वयन क्या है? हाइबरनेट के स्क्रॉल योग्य परिणामों का उपयोग करके 90 मिलियन रिकॉर्ड को धीरे-धीरे पढ़ा जा सके

क्या वास्तव में एक कारण है कि अतिभारित && और || शॉर्ट सर्किट न करें?

ऑपरेटरों के लघु सर्किटिंग व्यवहार && और || प्रोग्रामर के लिए एक अद्भुत टूल है

लेकिन ओवरलोड होने पर वे इस व्यवहार को क्यों खो देते हैं? मैं समझता हूं कि ऑपरेटर फ़ंक्शन के लिए केवल वाक्यात्मक चीनी हैं लेकिन bool के ऑपरेटरों के लिए यह व्यवहार है, इसे इस प्रकार एक ही प्रकार तक सीमित क्यों रखना चाहिए? क्या इसके पीछे कोई तकनीकी तर्क है?

Solutions Collecting From Web of "क्या वास्तव में एक कारण है कि अतिभारित && और || शॉर्ट सर्किट न करें?"

सभी डिजाइन प्रक्रियाएं पारस्परिक रूप से असंगत लक्ष्यों के बीच समझौता करती हैं। दुर्भाग्य से, सी ++ में अतिभारित && ऑपरेटर के लिए डिजाइन प्रक्रिया ने एक भ्रामक अंतिम परिणाम पेश किया: यह कि आप जिस सुविधा को && – उसके लघु-सर्किट व्यवहार से चाहते हैं – को छोड़ा गया है।

कैसे इस डिजाइन प्रक्रिया को इस दुर्भाग्यपूर्ण जगह में समाप्त हो गया, इसका विवरण, मुझे नहीं पता है। हालांकि यह देखने के लिए प्रासंगिक है कि बाद में डिजाइन प्रक्रिया ने इस अप्रिय परिणाम को ध्यान में कैसे ले लिया। सी # में, अतिभारित && ऑपरेटर कम सर्किटिंग है सी # के डिज़ाइनर ने इसे कैसे हासिल किया?

अन्य जवाबों में से एक में "लैम्ब्डा उठाने" का सुझाव दिया गया है अर्थात्:

 A && B 

नैतिक रूप से कुछ के रूप में महसूस किया जा सकता है:

 operator_&& ( A, ()=> B ) 

जहां दूसरा तर्क आलसी मूल्यांकन के लिए कुछ तंत्र का उपयोग करता है ताकि मूल्यांकन किए जाने पर, अभिव्यक्ति के साइड इफेक्ट्स और मूल्य का उत्पादन किया जाए। ओवरलोड किए गए ऑपरेटर के कार्यान्वयन केवल जब आवश्यक हो, आलसी मूल्यांकन करेगा।

यह नहीं है कि सी # डिजाइन टीम ने क्या किया। (एक तरफ: यद्यपि लैंबडा उठाने का काम है, जब मैंने समय दिया था, जब ऑपरेटर के अभिव्यक्ति के पेड़ का प्रतिनिधित्व करने के लिए समय आया था, जिसके लिए कुछ रूपांतरण कार्यों की आवश्यकता होती है, जो आलोक रूप से करने की आवश्यकता होती है। यह बताते हुए कि विस्तृत रूप से एक प्रमुख विषयांतर होगा। लैम्ब्डा लिफ्टिंग काम करता है लेकिन पर्याप्त रूप से भारी है कि हम इसे टालना चाहते थे।)

बल्कि, सी # समाधान ने समस्या को दो अलग-अलग समस्याओं में तोड़ दिया है:

  • क्या हमें दाहिनी हाथों का मूल्यांकन करना चाहिए?
  • अगर उपरोक्त उत्तर "हां" था, तो हम दो ऑपरेंडों को कैसे संयोजित करते हैं?

इसलिए इस समस्या को अवैध रूप से अधिभार && सीधा रूप से बनाकर हल किया जाता है। बल्कि, सी # में आप दो ऑपरेटरों को अधिभार लेंगे, जिनमें से प्रत्येक उन दो सवालों के जवाब देंगे।

 class C { // Is this thing "false-ish"? If yes, we can skip computing the right // hand size of an && public static bool operator false (C c) { whatever } // If we didn't skip the RHS, how do we combine them? public static C operator & (C left, C right) { whatever } ... 

(एक तरफ: वास्तव में, तीन। सी # की आवश्यकता है कि अगर ऑपरेटर false प्रदान किया जाता है तो ऑपरेटर true भी प्रदान किया जाना चाहिए, जो प्रश्न का उत्तर देता है: क्या यह बात "सच-इश?" है। आमतौर पर केवल एक ऐसे ऑपरेटर प्रदान करने का कोई कारण नहीं होगा इसलिए सी # दोनों की आवश्यकता है।)

प्रपत्र के एक बयान पर विचार करें:

 C cresult = cleft && cright; 

कंपाइलर इसके लिए कोड उत्पन्न करता है जैसा कि आपने यह छद्म सी # लिखा है:

 C cresult; C tempLeft = cleft; cresult = C.false(tempLeft) ? tempLeft : C.&(tempLeft, cright); 

जैसा कि आप देख सकते हैं, बाएं हाथ की ओर हमेशा मूल्यांकन किया जाता है। यदि यह "झूठी-इश" होने का निर्धारण किया जाता है तो यह परिणाम है। अन्यथा, दाहिनी ओर का मूल्यांकन किया जाता है, और उत्सुक यूज़र-डिफ़ाइंड ऑपरेटर & इसे लागू किया जाता है।

|| ऑपरेटर को समान तरीके से परिभाषित किया गया है, जैसा कि ऑपरेटर सही और उत्सुक के एक आवाहन के रूप में है | ऑपरेटर:

 cresult = C.true(tempLeft) ? tempLeft : C.|(tempLeft , cright); 

सभी चार ऑपरेटरों को परिभाषित करके – true , false , & – सी # आपको cleft & cright ही नहीं बल्कि नॉन-शॉर्ट सर्किटिंग cleft & cright को भी cleft & cright , और if (cleft) if (cright) ... और c ? consequence : alternative c ? consequence : alternative और while(c) , और इतने पर

अब, मैंने कहा कि सभी डिजाइन प्रक्रियाएं समझौता का परिणाम हैं। यहां सी # भाषा डिजाइनरों को शॉर्ट-सर्किटिंग एंड एंड और || ठीक है, लेकिन ऐसा करने से दो लोगों के बजाय चार ऑपरेटरों को ओवरलोड करना पड़ता है, जो कुछ लोगों को भ्रमित करने लगता है। ऑपरेटर सच / झूठी सुविधा सी # में कम से कम अच्छी तरह से समझी जाने वाली सुविधाओं में से एक है। सी ++ उपयोगकर्ताओं से परिचित होने वाली समझदार और सरल भाषा रखने का लक्ष्य कम परिपाटी और लैम्ब्डा उठाने या आलसी मूल्यांकन के अन्य रूपों को लागू नहीं करने की इच्छाओं के लिए इच्छाओं का विरोध किया गया था। मुझे लगता है कि यह एक उचित समझौता स्थिति थी, लेकिन यह समझना महत्वपूर्ण है कि यह समझौता स्थिति है। बस सी + + के डिजाइनरों की तुलना में एक अलग समझौता स्थिति।

यदि इस प्रकार के ऑपरेटरों के लिए भाषा डिजाइन का विषय आपको दिलचस्पी लेता है, तो मेरी सीरीज़ को पढ़ने पर विचार करें कि क्यों सी # इन बकाया बुलियन पर इन ऑपरेटरों को परिभाषित नहीं करता है:

http://ericlippert.com/2012/03/26/null-is-not-false-part-one/

मुद्दा यह है कि (सी + + 98 की सीमा के भीतर) दायां हाथ के ऑपरेंड को ओवरलोडेड ऑपरेटर फ़ंक्शन को तर्क के रूप में पारित किया जाएगा। ऐसा करने में, यह पहले से ही मूल्यांकन किया जाएगाoperator||() या operator&&() कोड कुछ भी नहीं है या ऐसा नहीं कर सकता जो इससे बचने के लिए होगा

मूल ऑपरेटर अलग है, क्योंकि यह फ़ंक्शन नहीं है, लेकिन भाषा के निचले स्तर पर कार्यान्वित किया गया है।

अतिरिक्त भाषा की विशेषताओं ने दाहिनी ओर के ऑपरैण्ड का नॉन-मूल्यांकन किया है जो वाक्यविन्यास रूप से संभव है । हालांकि, वे परेशान नहीं थे क्योंकि केवल कुछ ही चुनिंदा मामलों में ही यह अर्थपूर्ण रूप से उपयोगी होगा। (बस की तरह ? : , जो सभी के लिए ओवरलोडिंग के लिए उपलब्ध नहीं है

(लैंबडा को मानक में लाने के लिए उन्हें 16 साल लग गए …)

अर्थपूर्ण उपयोग के लिए, विचार करें:

 objectA && objectB 

यह नीचे फोड़े:

 template< typename T > ClassA.operator&&( T const & objectB ) 

इस बारे में सोचें कि आप ऑब्जेक्टबब (अज्ञात प्रकार) के साथ क्या करना चाहते हैं, एक रूपांतरण ऑपरेटर को bool करने के अलावा और आप भाषा परिभाषा के लिए शब्दों में कैसे डालते हैं

और अगर आप रूपांतरण के लिए बुल को बुला रहे हैं , तो …

 objectA && obectB 

वही करता है, अब क्या करता है? तो पहली जगह में अधिभार क्यों?

एक सुविधा के बारे में सोचना, डिजाइन, कार्यान्वित, दस्तावेज और भेज दिया जाना चाहिए।

अब हम इसके बारे में सोचा, चलो देखते हैं कि यह अब आसान क्यों हो सकता है (और तब करना कठिन है) यह भी ध्यान में रखें कि सीमित संसाधनों का केवल इतना ही सीमित हिस्सा है, इसलिए इसमें कुछ और कटा हुआ हो सकता है (आप इसके लिए क्या करना चाहते हैं?)


सिद्धांत रूप में, सभी ऑपरेटर 1 9 7 9 में शुरू होने वाले "कक्षाओं के साथ सी" के 32 साल बाद, जब भी लम्ब्दास पेश किया गया था, केवल एक "छोटी" अतिरिक्त भाषा-सुविधा के साथ ही शॉर्ट सर्किट व्यवहार की अनुमति हो सकती थी, फिर भी सम्मानजनक 16 सी ++ 98 के बाद):

सी ++ को तर्क के रूप में आलसी-मूल्यांकन – एक छिपे-लैम्ब्डा के रूप में व्याख्या करने की आवश्यकता होगी – जब तक कि आवश्यक और अनुमति (पूर्व शर्तों से मिले) तक मूल्यांकन से बचने के लिए।


उस सैद्धांतिक विशेषता क्या दिखती है (याद रखें कि कोई भी नई सुविधाएं व्यापक रूप से उपयोग की जानी चाहिए)?

एक एनोटेशन lazy , जो एक फ़ंक्शन-तर्क के लिए आवेदन करता है, एक फ़ैक्टक्टर की अपेक्षा टेम्पलेट को फ़ंक्शन बनाता है, और कम्पाइलर को एक फ़ैक्टर में अभिव्यक्ति को पैक करता है:

 A operator&&(B b, __lazy C c) {return c;} // And be called like exp_b && exp_c; // or operator&&(exp_b, exp_c); 

यह कवर की तरह नीचे दिखेगा:

 template<class Func> A operator&&(B b, Func& f) {auto&& c = f(); return c;} // With `f` restricted to no-argument functors returning a `C`. // And the call: operator&&(exp_b, [&]{return exp_c;}); 

विशेष ध्यान दें कि लम्ब्डा छिपा रहता है, और इसे सबसे अधिक बार बुलाया जाएगा।
इस वजह से कोई प्रदर्शन-गिरावट नहीं होनी चाहिए, इसके अलावा आम-कम-निष्कासन-उन्मूलन की संभावनाएं कम होनी चाहिए।


कार्यान्वयन-जटिलता और वैचारिक जटिलता के अलावा (हर सुविधा दोनों बढ़ जाती है, जब तक कि कुछ अन्य विशेषताओं के लिए उन जटिलताओं को पर्याप्त रूप से आसान नहीं किया जाता है), हम एक और महत्वपूर्ण विचार को देखें: पीछे की ओर-संगतता

हालांकि यह भाषा-सुविधा किसी भी कोड को नहीं तोड़ सकती है, लेकिन यह किसी भी एपीआई का फायदा उठाकर इसे काफ़ी बदल देगा, जिसका अर्थ है कि मौजूदा पुस्तकालयों में कोई भी उपयोग एक चुप्पी तोड़ने वाला परिवर्तन होगा।

बीटीडब्लू: यह सुविधा, जबकि उपयोग करना आसान है, सी # समाधान के बंटवारे && और || से कड़ाई से मजबूत है अलग-अलग परिभाषा के लिए प्रत्येक दो कार्यों में

पूर्वव्यापी युक्तिकरण के साथ, मुख्यतः क्योंकि

  • गारंटीकृत शॉर्ट सर्किट के लिए (नए सिंटैक्स को शुरू किए बिना) ऑपरेटर को प्रतिबंधित करना होगा परिणाम वास्तविक पहला तर्क परिवर्तनीय टू bool , और

  • छोटे सर्किटिंग को अन्य तरीकों से आसानी से व्यक्त किया जा सकता है, जब आवश्यक हो।


उदाहरण के लिए, यदि एक वर्ग T ने && और || ऑपरेटरों, तो अभिव्यक्ति

 auto x = a && b || c; 

जहां a , b और c प्रकार T की अभिव्यक्ति हैं, को लघु सर्किटिंग के साथ व्यक्त किया जा सकता है

 auto&& and_arg = a; auto&& and_result = (and_arg? and_arg && b : and_arg); auto x = (and_result? and_result : and_result || c); 

या शायद अधिक स्पष्ट रूप से

 auto x = [&]() -> T_op_result { auto&& and_arg = a; auto&& and_result = (and_arg? and_arg && b : and_arg); if( and_result ) { return and_result; } else { return and_result || b; } }(); 

स्पष्ट अतिरेक ऑपरेटर निमंत्रण से किसी भी पक्ष-प्रभाव को सुरक्षित रखता है।


जबकि लैम्ब्डा पुनर्लेखन अधिक शब्दबोधक है, इसके बेहतर एनकॉप्शन एक ऐसे ऑपरेटरों को परिभाषित करने की अनुमति देता है।

मैं पूरी तरह से निम्नलिखित सभी के मानक-अनुरूपता (इंफ्लुएंसा का एक बिट) के बारे में निश्चित नहीं हूं, लेकिन यह विज़ुअल सी ++ 12.0 (2013) और मिनजीड जी ++ 4.8.2 के साथ साफ तरीके से संकलित है:

 #include <iostream> using namespace std; void say( char const* s ) { cout << s; } struct S { using Op_result = S; bool value; auto is_true() const -> bool { say( "!! " ); return value; } friend auto operator&&( S const a, S const b ) -> S { say( "&& " ); return a.value? b : a; } friend auto operator||( S const a, S const b ) -> S { say( "|| " ); return a.value? a : b; } friend auto operator<<( ostream& stream, S const o ) -> ostream& { return stream << o.value; } }; template< class T > auto is_true( T const& x ) -> bool { return !!x; } template<> auto is_true( S const& x ) -> bool { return x.is_true(); } #define SHORTED_AND( a, b ) \ [&]() \ { \ auto&& and_arg = (a); \ return (is_true( and_arg )? and_arg && (b) : and_arg); \ }() #define SHORTED_OR( a, b ) \ [&]() \ { \ auto&& or_arg = (a); \ return (is_true( or_arg )? or_arg : or_arg || (b)); \ }() auto main() -> int { cout << boolalpha; for( int a = 0; a <= 1; ++a ) { for( int b = 0; b <= 1; ++b ) { for( int c = 0; c <= 1; ++c ) { S oa{!!a}, ob{!!b}, oc{!!c}; cout << a << b << c << " -> "; auto x = SHORTED_OR( SHORTED_AND( oa, ob ), oc ); cout << x << endl; } } } } 

आउटपुट:

 000 -> !!  !!  ||  असत्य
 001 -> !!  !!  ||  सच
 010 -> !!  !!  ||  असत्य
 011 -> !!  !!  ||  सच
 100 -> !!  && !!  ||  असत्य
 101 -> !!  && !!  ||  सच
 110 -> !!  && !!  सच
 111 -> !!  && !!  सच

यहाँ प्रत्येक !! बैंग-बैंग, एक रूपांतरण को bool दिखाता है, अर्थात् तर्क मूल्य जांच।

चूंकि एक कंपाइलर आसानी से ऐसा कर सकता है, और इसके अतिरिक्त अनुकूलन कर सकता है, यह एक संभावित संभव कार्यान्वयन है और समान श्रेणी में असंभवता का कोई भी दायित्व सामान्य रूप से असंबंधित दावों के रूप में रखा जाना चाहिए, अर्थात् आम तौर पर बोल्क्स।

tl; dr : बहुत कम मांग (जो इस सुविधा का प्रयोग करेंगे) के कारण, उच्च लागत (विशेष सिंटैक्स की आवश्यकता) की तुलना में यह प्रयास के लायक नहीं है।

पहली बात जो मन में आती है वह यह है कि ऑपरेटर ओवरलोडिंग फ़ंक्शन लिखने का एक शानदार तरीका है, जबकि ऑपरेटरों के बूलीयन संस्करण || और && buitlin सामान हैं इसका मतलब है कि संकलक को शॉर्ट-सर्किट के लिए स्वतंत्रता है, जबकि एक्सब्स x = y && z को गैरबोलीयन y और z साथ X operator&& (Y, Z) और एंड X operator&& (Y, Z) जैसे फ़ंक्शन को कॉल करना है। इसका मतलब यह होगा कि y && z operator&&(y,z) लिखने का एक शानदार तरीका है operator&&(y,z) जो कि एक अजीब नामित फ़ंक्शन की कॉल है, जहां दोनों मापदंडों को समारोह कॉल करने से पहले मूल्यांकन किया जाना है (जिसमें कोई भी शॉर्ट- सर्क्युटिंग एपप्रिएट)

हालांकि, कोई तर्क दे सकता है कि && ऑपरेटर के अनुवाद को && अधिक परिष्कृत करने के लिए संभव होना चाहिए, जैसे कि यह new ऑपरेटर के लिए है जिसे फ़ंक्शन operator new को कॉल करने के लिए अनुवादित किया गया है, जिसके बाद कन्स्ट्रक्टर कॉल किया गया है।

तकनीकी तौर पर यह कोई समस्या नहीं होगी, एक पूर्व शर्त के लिए एक भाषा वाक्यविन्यास विशिष्ट परिभाषित करना होगा जो लघु-सर्किट को सक्षम करता है हालांकि, शॉर्ट-सर्किट का उपयोग उन मामलों तक सीमित होगा जहां Y को X लिए माना जा सकता है, या फिर अतिरिक्त सर्टिविटिंग करने के लिए अतिरिक्त जानकारी होनी चाहिए (यानी केवल पहले पैरामीटर से परिणाम की गणना करना)। परिणाम कुछ इस तरह देखना होगा:

 X operator&&(Y const& y, Z const& z) { if (shortcircuitCondition(y)) return shortcircuitEvaluation(y); <"Syntax for an evaluation-Point for z here"> return actualImplementation(y,z); } 

एक शायद ही कभी अधिभार operator|| करना चाहता है operator|| और operator&& , क्योंकि वहां शायद ही कोई मामला है जहां a && b लिखने वास्तव में एक गैरबोलीय संदर्भ में सहज है। एकमात्र अपवाद जो मैं जानता हूं अभिव्यक्ति टेम्पलेट्स हैं, जैसे एम्बेडेड डीएसएल के लिए और उन कुछ मामलों में केवल मुट्ठी भर शॉर्ट सर्किट मूल्यांकन से लाभ होगा। अभिव्यक्ति टेम्पलेट आमतौर पर नहीं करते, क्योंकि वे अभिव्यक्ति के पेड़ बनाने के लिए उपयोग किए जाते हैं जिन्हें बाद में मूल्यांकन किया जाता है, इसलिए आपको हमेशा अभिव्यक्ति के दोनों तरफ की आवश्यकता होती है।

संक्षेप में: न तो कंपाइलर लेखकों और न ही मानकों के लेखकों ने हुप्स के माध्यम से कूदने और अतिरिक्त बोझिल सिंटैक्स को परिभाषित करने और लागू करने की आवश्यकता महसूस की, क्योंकि सिर्फ दस लाख में ही यह विचार हो सकता है कि उपयोगकर्ता परिभाषित operator&& और operator|| पर शॉर्ट सर्किट होना अच्छा होगा। operator|| – बस इस निष्कर्ष पर पहुंचने के लिए कि तर्क प्रति हाथ लिखने की तुलना में यह कम प्रयास नहीं है।

तार्किक ऑपरेटरों को लघु सर्किट करने की अनुमति दी जाती है क्योंकि यह संबद्ध सत्य तालिकाओं के मूल्यांकन में "अनुकूलन" है यह तर्क का एक कार्य है, और यह तर्क परिभाषित किया गया है।

क्या वास्तव में एक कारण है कि अतिभारित && और || शॉर्ट सर्किट न करें?

कस्टम अतिभारित तार्किक ऑपरेटर इन सच्चाई तालिकाओं के तर्क का पालन करने के लिए बाध्य नहीं हैं।

लेकिन ओवरलोड होने पर वे इस व्यवहार को क्यों खो देते हैं?

इसलिए पूरे समारोह को सामान्य के अनुसार मूल्यांकन किया जाना चाहिए। संकलक को इसे सामान्य ओवरलोडेड ऑपरेटर (या फ़ंक्शन) के रूप में रखना चाहिए और यह अभी भी अनुकूलन लागू कर सकता है क्योंकि यह किसी अन्य फ़ंक्शन के साथ होगा।

लोग विभिन्न कारणों से तार्किक ऑपरेटरों को अधिभार देते हैं। उदाहरण के लिए; उनके पास एक विशिष्ट डोमेन में विशिष्ट अर्थ हो सकता है जो कि "सामान्य" तार्किक लोगों के लिए अभ्यस्त नहीं हैं

"और" और "या" की सत्य तालिका के कारण शॉर्ट-सर्किटिंग है आपको कैसे पता चलेगा कि उपयोगकर्ता किस आपरेशन को परिभाषित करेगा और आप कैसे जानते होंगे कि आपको दूसरे ऑपरेटर का मूल्यांकन नहीं करना पड़ेगा?

लम्बेदा आलस्य को पेश करने का एकमात्र तरीका नहीं है आलसी मूल्यांकन सी ++ में अभिव्यक्ति टेम्पलेट्स का इस्तेमाल करते हुए अपेक्षाकृत सीधे-आगे है खोजशब्द lazy की कोई ज़रूरत नहीं है और इसे सी ++ 98 में लागू किया जा सकता है। अभिव्यक्ति के पेड़ पहले ही उल्लेख हैं अभिव्यक्ति टेम्पलेट खराब (लेकिन चतुर) मनुष्य के अभिव्यक्ति पेड़ हैं चाल एक्सप्रेशन टेम्प्लेट के Expr नेस्टेड इंस्टीटयेशंस के पेड़ में अभिव्यक्ति को परिवर्तित करने के लिए है। पेड़ के निर्माण के बाद अलग से मूल्यांकन किया जाता है

निम्न कोड शॉर्ट-सर्किट && और || वर्ग S लिए ऑपरेटर जब तक यह logical_and logical_or फ़ंक्शंस प्रदान करता है और यह bool लिए परिवर्तनीय है bool कोड सी ++ 14 में है लेकिन यह विचार सी ++ 98 में भी लागू है। लाइव उदाहरण देखें

 #include <iostream> struct S { bool val; explicit S(int i) : val(i) {} explicit S(bool b) : val(b) {} template <class Expr> S (const Expr & expr) : val(evaluate(expr).val) { } template <class Expr> S & operator = (const Expr & expr) { val = evaluate(expr).val; return *this; } explicit operator bool () const { return val; } }; S logical_and (const S & lhs, const S & rhs) { std::cout << "&& "; return S{lhs.val && rhs.val}; } S logical_or (const S & lhs, const S & rhs) { std::cout << "|| "; return S{lhs.val || rhs.val}; } const S & evaluate(const S &s) { return s; } template <class Expr> S evaluate(const Expr & expr) { return expr.eval(); } struct And { template <class LExpr, class RExpr> S operator ()(const LExpr & l, const RExpr & r) const { const S & temp = evaluate(l); return temp? logical_and(temp, evaluate(r)) : temp; } }; struct Or { template <class LExpr, class RExpr> S operator ()(const LExpr & l, const RExpr & r) const { const S & temp = evaluate(l); return temp? temp : logical_or(temp, evaluate(r)); } }; template <class Op, class LExpr, class RExpr> struct Expr { Op op; const LExpr &lhs; const RExpr &rhs; Expr(const LExpr& l, const RExpr & r) : lhs(l), rhs(r) {} S eval() const { return op(lhs, rhs); } }; template <class LExpr> auto operator && (const LExpr & lhs, const S & rhs) { return Expr<And, LExpr, S> (lhs, rhs); } template <class LExpr, class Op, class L, class R> auto operator && (const LExpr & lhs, const Expr<Op,L,R> & rhs) { return Expr<And, LExpr, Expr<Op,L,R>> (lhs, rhs); } template <class LExpr> auto operator || (const LExpr & lhs, const S & rhs) { return Expr<Or, LExpr, S> (lhs, rhs); } template <class LExpr, class Op, class L, class R> auto operator || (const LExpr & lhs, const Expr<Op,L,R> & rhs) { return Expr<Or, LExpr, Expr<Op,L,R>> (lhs, rhs); } std::ostream & operator << (std::ostream & o, const S & s) { o << s.val; return o; } S and_result(S s1, S s2, S s3) { return s1 && s2 && s3; } S or_result(S s1, S s2, S s3) { return s1 || s2 || s3; } int main(void) { for(int i=0; i<= 1; ++i) for(int j=0; j<= 1; ++j) for(int k=0; k<= 1; ++k) std::cout << and_result(S{i}, S{j}, S{k}) << std::endl; for(int i=0; i<= 1; ++i) for(int j=0; j<= 1; ++j) for(int k=0; k<= 1; ++k) std::cout << or_result(S{i}, S{j}, S{k}) << std::endl; return 0; } 

लेकिन bool के ऑपरेटरों के लिए यह व्यवहार है, इसे इस एकल प्रकार तक सीमित क्यों होना चाहिए?

मैं सिर्फ इस एक भाग का जवाब देना चाहता हूं। इसका कारण यह है कि अंतर्निहित && और || अतिभारित ऑपरेटरों के रूप में कार्य निष्पादित नहीं किए जाते हैं।

विशिष्ट अभिव्यक्ति की संकलक की समझ में अंतर्निहित शॉर्ट सर्किट लॉजिक होने के लिए आसान है। यह किसी भी अन्य अंतर्निहित नियंत्रण प्रवाह की तरह है।

लेकिन ऑपरेटर ओवरलोडिंग को इसके बजाय कार्य के साथ लागू किया जाता है, जिसमें विशेष नियम हैं, जिनमें से एक यह है कि फ़ंक्शन के नाम से पहले तर्क के रूप में इस्तेमाल किए गए सभी भाव का मूल्यांकन किया जाता है। स्पष्ट रूप से विभिन्न नियमों को परिभाषित किया जा सकता है, लेकिन यह एक बड़ा काम है