दिलचस्प पोस्ट
मानचित्र क्या है? डिस्पेचटॉप्रॉप? ES6 / Typecript में तीर फ़ंक्शन के साथ _ (अंडरस्कोर) वैरिएबल का उपयोग करना एंड्रॉइड – java.lang.SecurityException: अनुमति अस्वीकृति: शुरुआती आशय log4j: सॉकेट अपैपर का उपयोग कैसे करें? स्प्रिंग एमवीसी – स्प्रिंग नियंत्रक के नक्शे में सभी अनुरोध पैरामीटर कैसे प्राप्त करें? PHP, MySQL डाटाबेस में कई चेकबॉक्स और टेक्स्टबॉक्स सरणी डालने SQLite में वैरिएबल तालिका का नाम C ++ – GetUserName () जब प्रक्रिया व्यवस्थापक के रूप में चलाया जाता है अमान्य XML वर्णों को सी # में से बचें क्या कोणीय मार्गों के वैकल्पिक पैरामीटर मान हैं? एक्लिप्स लॉन्च के साथ "java.library.path" को देशी लाइब्रेरी कैसे जोड़ना है (ओवरराइड करने के बजाय) सी # में स्थिर पैरामीटर की अनुमति क्यों नहीं है? दस्तावेज़ के साथ इसे लिखते समय <script> टैग को विभाजित क्यों करें? लिखना ()? गैर-प्राथमिक कुंजी के लिए विदेशी कुंजी वेबसाइटों पर सूचना ध्वनि कैसे खेलें?

विविधतापूर्ण टेम्पलेट पैक विस्तार

मैं variadic टेम्पलेट्स और कार्यों को जानने की कोशिश कर रहा हूँ मुझे समझ में नहीं आ रहा है कि यह कोड क्यों संकलित नहीं करता है:

template<typename T> static void bar(T t) {} template<typename... Args> static void foo2(Args... args) { (bar(args)...); } int main() { foo2(1, 2, 3, "3"); return 0; } 

जब मैं संकलन करता हूं तो त्रुटि के साथ विफल रहता है:

त्रुटि C3520: 'आर्ग्स': पैरामीटर पैक इस संदर्भ में विस्तारित होना चाहिए

(फ़ंक्शन में foo2 )

वेब के समाधान से एकत्रित समाधान "विविधतापूर्ण टेम्पलेट पैक विस्तार"

उन जगहों में से एक, जहां एक पैक विस्तार हो सकता है, एक ब्रैकेट-इनिट-सूची के अंदर है। आप एक डमी सरणी के प्रारंभिक सूची के अंदर विस्तार डालकर इस का लाभ उठा सकते हैं:

 template<typename... Args> static void foo2(Args &&... args) { int dummy[] = { 0, ( (void) bar(std::forward<Args>(args)), 0) ... }; } 

अधिक विवरण में प्रारंभकर्ता की सामग्री की व्याख्या करने के लिए:

 { 0, ( (void) bar(std::forward<Args>(args)), 0) ... }; | | | | | | | | | --- pack expand the whole thing | | | | | | --perfect forwarding --- comma operator | | | -- cast to void to ensure that regardless of bar()'s return type | the built-in comma operator is used rather than an overloaded one | ---ensure that the array has at least one element so that we don't try to make an illegal 0-length array when args is empty 

डेमो

{} में विस्तार करने का एक महत्वपूर्ण लाभ यह है कि यह बाएं से सही मूल्यांकन की गारंटी देता है


सी ++ 1z गुना अभिव्यक्ति के साथ , आप बस लिख सकते हैं

 ((void) bar(std::forward<Args>(args)), ...); 

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

अंगूठे का नियम है "विस्तार एक सूची तैयार कर सकता है , -निष्कृत पैटर्न , जहां एक सूची सीमांकक है।" ऑपरेटर , व्याकरण के अर्थ में एक सूची तैयार नहीं करता है

प्रत्येक तर्क के लिए फ़ंक्शन कॉल करने के लिए, आप पुनरावर्तन का उपयोग कर सकते हैं (जो कि वैराइडीक टेम्पलेट प्रोग्रामर के बॉक्स में प्राथमिक उपकरण है):

 template <typename T> void bar(T t) {} void foo2() {} template <typename Car, typename... Cdr> void foo2(Car car, Cdr... cdr) { bar(car); foo2(cdr...); } int main() { foo2 (1, 2, 3, "3"); } 

लाइव उदाहरण

शर्मनाक कॉपी [अपने स्रोत द्वारा अनुमोदित]

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

अंगूठे का नियम है "विस्तार एक सूची तैयार कर सकता है , -निष्कृत पैटर्न , जहां एक सूची सीमांकक है।" ऑपरेटर , व्याकरण के अर्थ में एक सूची तैयार नहीं करता है

प्रत्येक तर्क के लिए फ़ंक्शन कॉल करने के लिए, आप पुनरावर्तन का उपयोग कर सकते हैं (जो कि वैराइडीक टेम्पलेट प्रोग्रामर के बॉक्स में प्राथमिक उपकरण है):

 #include <utility> template<typename T> void foo(T &&t){} template<typename Arg0, typename Arg1, typename ... Args> void foo(Arg0 &&arg0, Arg1 &&arg1, Args &&... args){ foo(std::forward<Arg0>(arg0)); foo(std::forward<Arg1>(arg1), std::forward<Args>(args)...); } auto main() -> int{ foo(1, 2, 3, "3"); } 

उपयोगी गैर-सम्पन्न जानकारी

एक और चीज जिसे आपने शायद इस उत्तर में नहीं देखा है && specifier और std::forward सी ++ में, एंड एक्स स्पेसिफ़र का अर्थ 2 चीजों में से एक हो सकता है: rvalue-references, या सार्वभौमिक संदर्भ।

मैं rvalue- संदर्भ में नहीं जाना होगा, लेकिन variadic टेम्पलेट्स के साथ काम कर रहे किसी को; सार्वभौमिक संदर्भ एक ईश्वर भेजने हैं।

सही अग्रेषण

std::forward और सार्वभौमिक संदर्भों में से एक का उपयोग अन्य कार्यों में प्रकारों का सही फ़ॉरवर्डिंग है।

आपके उदाहरण में, यदि हम एक int& foo2 को पास करते हैं तो टेम्पलेट कटौती के बाद उत्पन्न foo2 फ़ंक्शन के हस्ताक्षर के कारण इसे स्वचालित रूप से int लिए foo2 दिया जाएगा और यदि आप चाहते हैं कि इस arg को अन्य फ़ंक्शन को अग्रेषित करें जो इसे एनई संदर्भ संशोधित करे, तो आप अवांछित परिणाम प्राप्त होंगे (चर परिवर्तित नहीं किया जाएगा) क्योंकि foo2 एक int को पास करके बनाए गए अस्थायी संदर्भ को पारित करेगा। इसके चारों ओर पाने के लिए, हम एक चर (rvalue या lvalue) के किसी भी प्रकार के संदर्भ को लेने के लिए अग्रेषण फ़ंक्शन निर्दिष्ट करते हैं। फिर, यह सुनिश्चित करने के लिए कि हम अग्रेषण फ़ंक्शन में दिए गए सटीक प्रकार को पास करते हैं, जो हम std::forward उपयोग करते std::forward , और तब ही हम प्रकारों के डिमोडिंग की अनुमति देते हैं; क्योंकि हम उस बिंदु पर हैं जहां यह सबसे महत्वपूर्ण है।

यदि आप की आवश्यकता है, सार्वभौमिक संदर्भ और सही फ़ॉरवर्डिंग पर और अधिक पढ़ें; स्कॉट मैयर्स एक संसाधन के रूप में बहुत अच्छा है

आप पैक विस्तार के लिए make_tuple उपयोग कर सकते हैं क्योंकि यह एक संदर्भ प्रस्तुत करता है , जहां विस्तार द्वारा उत्पादित अनुक्रम मान्य है

 make_tuple( (bar(std::forward<Args>(args)), 0)... ); 

अब, मुझे संदेह है कि जेनर के अप्रयुक्त / अज्ञात / अस्थायी ट्यूपल का निर्माण किया गया है जो कंपाइलर के द्वारा detactable और अनुकूलित किया गया है

डेमो

इस के लिए निष्पादन आदेश की गारंटी नहीं है!

 make_tuple( (bar(std::forward<Args>(args)), 0)... ); 

इस उदाहरण में मापदंडों को कम से कम जीसीसी के साथ रिवर्स ऑर्डर में प्रिंट किया जाएगा।

 foo2(1, 2, 3, "3"); calling bar for 3 calling bar for 3 calling bar for 2 calling bar for 1