दिलचस्प पोस्ट
.NET पर डबल सटीक समस्याएं Android में एक JSON ऑब्जेक्ट को पार्स कैसे करें कैसे ठीक करें: "यूनिकोडडेकोडएअर: 'एएससीआई' कोडेक बाइट डीकोड नहीं कर सकता है" एक ईवेंट हैंडलर को रोकने के लिए सी # पैटर्न दो बार दोगुना स्विफ्ट 3.0: ऐरे या डिक्शनरी एक्स्टेंशन में वैश्विक मोनकॉम <टी> (टी, टी) को कॉल करते समय संकलक त्रुटि एंड्रॉइड अलर्ट डायलॉग में मैं सूची दृश्य कैसे दिखा सकता हूं? क्या एचटीएमएल <चयन करें> के लिए एक ऑनसाइट ऑब्जेक्ट या समतुल्य है? WAMP त्रुटि दिखाता है 'जब MSVCR100.dll' अनुपलब्ध है एंड्रॉइड में एचटीएमएल वेबपेज को स्क्रैप करने का सबसे तेज़ तरीका क्या है? क्या आपने सी ++ दुभाषियों (कंपाइलर नहीं) में से किसी का उपयोग किया है? क्या आपको कार्य करना है। इसे किसी भी तरीके से चलाने के लिए async करें? UIAppearance का उपयोग करके कस्टम आईओएस यूआईडेटिकपिकर कौन सा एक अच्छा अभ्यास है, एक शाब्दिक फ़ाइलशैली या एक टाइपोग्राफ? ViewPager पेजर एडाप्टर दृश्य को अपडेट नहीं कर रहा है सर्वश्रेष्ठ अभ्यास – जीआईटी + बिल्ड स्वचालन – अलग-अलग कॉन्फ़िगिंग रखना

कंस्ट्रक्टर से टेम्प्लेट पैरामीटर का अनुमान क्यों न करें?

मेरा प्रश्न आज बहुत आसान है: कक्षा कंस्ट्रक्टर से कंपाइलर अवधारक टेम्प्लेट पैरामीटर क्यों नहीं, उतना ही उतना ही हो सकता है जितना यह फ़ंक्शन पैरामीटर से कर सकता है? उदाहरण के लिए, निम्नलिखित कोड मान्य क्यों नहीं हो सकता है:

template<typename obj> class Variable { obj data; public: Variable(obj d) { data = d; } }; int main() { int num = 2; Variable var(num); //would be equivalent to Variable<int> var(num), return 0; //but actually a compile error } 

जैसा कि मैं कहता हूं, मैं समझता हूं कि यह मान्य नहीं है, इसलिए मेरा प्रश्न यह क्यों नहीं है? क्या यह किसी भी बड़े वाक्यविन्यास छेद बनाने की इजाजत दे सकता है? क्या ऐसा कोई उदाहरण है जहां कोई इस कार्यक्षमता नहीं चाहता है (जहां एक प्रकार का उल्लंघन करने से समस्याएं हो सकती हैं)? मैं कार्य के लिए टेम्पलेट निष्पादन को अनुमति देने के पीछे तर्क को समझने की कोशिश कर रहा हूं, फिर भी उपयुक्त-निर्माण कक्षाओं के लिए नहीं।

वेब के समाधान से एकत्रित समाधान "कंस्ट्रक्टर से टेम्प्लेट पैरामीटर का अनुमान क्यों न करें?"

मुझे लगता है कि यह मान्य नहीं है क्योंकि निर्माता हमेशा क्लास के प्रवेश का एकमात्र बिंदु नहीं है (मैं कॉपी कन्स्ट्रक्टर और ऑपरेटर = के बारे में बात कर रहा हूं)। तो मान लीजिए कि आप इस तरह अपनी कक्षा का उपयोग कर रहे हैं:

 MyClass m(string s); MyClass *pm; *pm = m; 

मुझे यकीन नहीं है कि पार्सर्स को पता होना चाहिए कि क्या टेम्प्लेट का प्रकार MyClass pm है;

निश्चित नहीं है कि अगर मैंने जो कहा, मुझे समझ में आ रहा है, लेकिन कुछ टिप्पणी जोड़ने में बेझिझक, यह एक दिलचस्प सवाल है

सी ++ 17

यह स्वीकार किया जाता है कि C ++ 17 में कन्स्ट्रक्टर आर्गेंस से टाइप कटौती होगी।

उदाहरण:

 std::pair p(2, 4.5); std::tuple t(4, 3, 2.5); 

स्वीकृत पेपर

आप अन्य लोगों द्वारा संबोधित किए गए कारणों के लिए आप क्या नहीं कर सकते, लेकिन आप ऐसा कर सकते हैं:

 template<typename T> class Variable { public: Variable(T d) {} }; template<typename T> Variable<T> make_variable(T instance) { return Variable<T>(instance); } 

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

एनबी: जब आप कुछ लिखते हैं, तो कोई उचित संकलक अस्थायी ऑब्जेक्ट को दूर कर देगा

 Variable<T> v = make_variable(instance); 

2016 के प्रबुद्ध युग में, हमारे बेल्ट के तहत दो नए मानकों के साथ इस प्रश्न के बारे में पूछा गया था और एक कोने के चारों ओर एक नया, महत्वपूर्ण बात यह जानती है कि C ++ 17 मानक का समर्थन करने वाले कंपाइलर आपके कोड को संकलित करेगा

सी ++ 17 में क्लास टेम्प्लेट के लिए टेम्पलेट-तर्क कटौती

यहां (स्वीकार्य उत्तर के ओल्झास झुमाबेक द्वारा संपादित किए गए शिष्टाचार) मानक के प्रासंगिक परिवर्तनों का विवरण देने वाला पेपर है।

अन्य उत्तर से चिंताओं को संबोधित करते हुए

मौजूदा टॉप रेटेड उत्तर

यह जवाब बताता है कि "कॉपी निर्माता और operator= " सही टेम्पलेट विशेषज्ञताओं को नहीं पता होगा।

यह बकवास है, क्योंकि मानक कॉपी-कन्स्ट्रक्टर और operator= केवल एक ज्ञात टेम्पलेट प्रकार के लिए मौजूद हैं :

 template <typename T> class MyClass { MyClass(const MyClass&) =default; ... etc... }; // usage example modified from the answer MyClass m(string("blah blah blah")); MyClass *pm; // WHAT IS THIS? *pm = m; 

यहां, जैसा कि मैंने टिप्पणियों में लिखा है, MyClass *pm लिए कोई नया अनुमान के साथ या बिना एक कानूनी घोषणा होने का कोई कारण नहीं है : MyClass एक प्रकार नहीं है (यह एक टेम्पलेट है), इसलिए यह समझ में नहीं आता है प्रकार के एक सूचक की घोषणा MyClass उदाहरण को ठीक करने का एक संभव तरीका यहां है:

 MyClassstring m("blah blah blah")); decltype(m) *pm; // uses type inference! *pm = m; 

यहां, pm पहले से सही प्रकार से है, और इसलिए अनुमान छोटा है। इसके अलावा, प्रतिलिपि-कन्स्ट्रक्टर को कॉल करते समय गलती से प्रकार के मिश्रण को असंभव है:

 MyClass m(string("blah blah blah")); auto pm = &(MyClass(m)); 

यहां, pm m की एक प्रति के लिए एक संकेतक होगा यहां, MyClass को कॉपी से बना दिया जा रहा है- जो कि MyClass<string> (और किसी न किसी तरह की MyClass ) की तरह है इस प्रकार, उस बिंदु पर जहां pm का प्रकार अनुमान लगाया गया है, यह जानने के लिए पर्याप्त जानकारी है कि टेम्पलेट-प्रकार m , और इसलिए टेम्पलेट-प्रकार का pm , string

इसके अलावा, निम्नलिखित हमेशा एक संकलन त्रुटि बढ़ाएगा :

 MyClass s(string("blah blah blah")); MyClass i(3); i = s; 

इसका कारण यह है कि प्रतिलिपि कन्स्ट्रक्टर की घोषणा नहीं की जाती है:

 MyClass(const MyClass&); 

यहां, कॉपी-कंस्ट्रक्टर तर्क का टेम्प्लेट-प्रकार समग्र क्लास के टेम्पलेट-प्रकार से मेल खाता है; यानी, जब MyClass<string> तत्काल होता है, MyClass<string>::MyClass(const MyClass<string>&); इसके साथ तत्काल, और जब MyClass<int> तत्काल होता है, MyClass<int>::MyClass(const MyClass<int>&); तत्काल है जब तक कि यह स्पष्ट रूप से निर्दिष्ट न हो या एक टेम्पलेटेटेड कन्स्ट्रक्टर घोषित किया गया हो, तो कंपाइलर के लिए MyClass<int>::MyClass(const MyClass<string>&); का कोई कारण नहीं है MyClass<int>::MyClass(const MyClass<string>&); , जो स्पष्ट रूप से अनुचित होगा

कोर्टलीन पिटीस द्वारा जवाब

Pitiş एक उदाहरण deducing Variable<int> और Variable<double> , तो कहता है:

मेरे पास दो अलग-अलग प्रकारों (वैरिएबल और वैरिएबल) के लिए कोड में समान प्रकार का नाम (वेरिएबल) है I मेरे व्यक्तिपरक दृष्टिकोण से, यह कोड की पठनीयता को बहुत ज्यादा प्रभावित करता है

जैसा कि पिछले उदाहरण में बताया गया है, Variable स्वयं एक प्रकार का नाम नहीं है, भले ही नई सुविधा यह एक वाक्यविन्यास की तरह दिखती है।

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

यह पूछे जाने जैसा है कि foo का कौन सा संस्करण यहाँ घटाना है:

 template <typename T> foo(); foo(); 

इसका उत्तर यह है कि यह कोड गैरकानूनी है, कारण के लिए कहा गया है।

MSalter का उत्तर

यह है, जहां तक ​​मैं बता सकता हूं, प्रस्तावित सुविधा के बारे में एक वैध चिंता लाने के लिए एकमात्र उत्तर है।

उदाहरण है:

 Variable var(num); // If equivalent to Variable<int> var(num), Variable var2(var); //Variable<int> or Variable<Variable<int>> ? 

मुख्य प्रश्न यह है कि क्या कंपाइलर यहां टाइप-अनुमानक कन्स्ट्रक्टर या प्रतिलिपि कन्स्ट्रक्टर का चयन करता है?

कोड को बाहर करने की कोशिश में, हम देख सकते हैं कि प्रतिलिपि निर्माता चयनित है। उदाहरण पर विस्तार करने के लिए :

 Variable var(num); // infering ctor Variable var2(var); // copy ctor Variable var3(move(var)); // move ctor // Variable var4(Variable(num)); // compiler error 

मुझे यकीन नहीं है कि कैसे प्रस्ताव और मानक का नया संस्करण यह निर्दिष्ट करता है; ऐसा लगता है कि "कटौती गाइड" द्वारा निर्धारित किया जाता है, जो मानक मानक के एक नए बिट हैं जिन्हें मैं अभी तक समझ नहीं पाया।

मुझे भी यकीन नहीं है कि var4 कटौती अवैध क्यों है; जी ++ से कंपाइलर त्रुटि यह इंगित करती है कि फ़ंक्शन घोषणा के रूप में कथन को पार्स किया जा रहा है।

अभी भी लापता है: यह निम्न कोड को काफी अस्पष्ट बना देता है:

 int main() { int num = 2; Variable var(num); // If equivalent to Variable<int> var(num), Variable var2(var); //Variable<int> or Variable<Variable<int>> ? } 

यह मानते हुए कि कंपाइलर आपके द्वारा पूछे जाने वाले का समर्थन करता है। तो यह कोड मान्य है:

 Variable v1( 10); // Variable<int> // Some code here Variable v2( 20.4); // Variable<double> 

अब, मेरे पास दो भिन्न प्रकारों (वैरिएबल और व्हेरिएबल) के लिए कोड में एक ही प्रकार का नाम (वेरिएबल) है। मेरे व्यक्तिपरक दृष्टिकोण से, यह कोड की पठनीयता को बहुत ज्यादा प्रभावित करता है एक ही नाम स्थान में दो अलग-अलग प्रकार के समान प्रकार का नाम मेरे लिए भ्रामक लग रहा है

बाद में अपडेट: विचार करने के लिए एक अन्य चीज: आंशिक (या पूर्ण) टेम्पलेट विशेषज्ञता

क्या होगा अगर मैं वैरिएबल का विशेषज्ञ हूं और आप की तरह कोई कन्स्ट्रक्टर नहीं दे सकता है?

तो मुझे ये होगा:

 template<> class Variable<int> { // Provide default constructor only. }; 

फिर मेरे पास कोड है:

 Variable v( 10); 

संकलक को क्या करना चाहिए? सामान्य वैरिएबल क्लास परिभाषा का उपयोग करने के लिए यह पता चला है कि वेरिएबल है, फिर पता चलता है कि वेरिएबल एक पैरामीटर कन्स्ट्रक्टर प्रदान नहीं करता है?

सी ++ 03 और सी +11 मानक कंस्ट्रक्टर को पास किए गए मानकों से टेम्पलेट अर्गलमेंट कटौती की अनुमति नहीं देता है।

लेकिन "कंस्ट्रक्शंस के लिए टेम्प्लेट पैरामीटर कटौती" के लिए एक प्रस्ताव है, ताकि आप जल्द से जल्द जो भी पूछ रहे हों संपादित करें: वास्तव में, यह सुविधा C ++ 17 के लिए पुष्टि की गई है

देखें: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3602.html और http://www.open-std.org/jtc1/sc22/wg21/docs/ कागजात / 2015 / p0091r0.html

बहुत सारे वर्ग कंसट्रेटर मापदंडों पर निर्भर नहीं करते हैं। केवल कुछ ही कक्षाएं हैं जिनके पास केवल एक कन्स्ट्रक्टर है, और इस निर्माता के प्रकार (एस) के आधार पर पैरामीराइज है।

यदि आपको वास्तव में टेम्पलेट अनुमान की आवश्यकता है, तो सहायक फ़ंक्शन का उपयोग करें:

 template<typename obj> class Variable { obj data; public: Variable(obj d) : data(d) { } }; template<typename obj> inline Variable<obj> makeVariable(const obj& d) { return Variable<obj>(d); } 

मौजूदा C ++ में प्रकारों का कटौती टेम्पलेट फ़्रेम्स तक सीमित है, लेकिन यह लंबे समय से यह महसूस किया गया है कि अन्य संदर्भों में टाइप कटौती बहुत उपयोगी होगी। इसलिए C ++ 0x auto

वास्तव में आप जिस सुझाव का सुझाव देते हैं, वह सी ++ 0x में संभव नहीं होगा, नीचे दिखाया गया है कि आप सुंदर बंद कर सकते हैं:

 template <class X> Variable<typename std::remove_reference<X>::type> MakeVariable(X&& x) { // remove reference required for the case that x is an lvalue return Variable<typename std::remove_reference<X>::type>(std::forward(x)); } void test() { auto v = MakeVariable(2); // v is of type Variable<int> } 

आप जो प्राप्त करने की कोशिश कर रहे हैं वह प्रकार एरर कहा जाता है बढ़ावा :: किसी भी पर एक नज़र डालें और इसका कार्यान्वयन यह कैसे काम करता है।

किसी भी बूस्ट करें

अब प्रश्न के लिए, यह काम क्यों नहीं करता है बढ़ावा देने के रूप में: कोई भी यह दर्शाता है कि लागू करना संभव है और यह काम करता है, लेकिन आपकी समस्या प्रेषण होगी जो वास्तव में अंदर है। टेम्पलेट दृष्टिकोण के विपरीत, आपको एप्लिकेशन रनटाइम पर प्रेषण करना होगा, क्योंकि निहित प्रकार मिट जाएगा। इसे संभालने के लिए 2 संभावनाएं हैं: विज़िटर पैटर्न और कस्टम कास्ट क्रियान्वयन (जो अपवाद को फेंकता है यदि आप गलत प्रकार की कोशिश कर रहे हैं)। दोनों मामलों में आप समय प्रकार की सुरक्षा को रनटाइम करने के लिए संकलित करते हैं और संकलक के प्रकार जांच को बायपास करते हैं।

एक और तरीका है कि वेरिएंट प्रकार: बूस्ट वैरिएंट को शुरू करना है

वेरिएंट को बढ़ावा देने के रूप में अलग तरह से कार्य करता है: किसी भी और संग्रहीत करने के लिए केवल सीमित प्रकार के प्रकार की अनुमति देता है। यह उच्च प्रकार की सुरक्षा का परिचय देता है, क्योंकि आप वास्तव में अपेक्षित प्रकारों के सेट को सीमित करते हैं। डीडीजे में एंड्री एलेक्जेंडरको द्वारा लिखी एक अच्छा लेख है, इस तरह के एक संस्करण को लागू करने के तरीके पर: भाग 1 , भाग 2 , भाग 3

यह कार्यान्वयन थोड़ा अधिक जटिल है, जैसे कि बढ़ावा :: कोई भी, लेकिन उच्च प्रकार की सुरक्षा प्रदान करता है और उपयोगकर्ताओं को स्पष्ट रूप से घोषित किए जाने वाले अपवादों के साथ, किसी भी प्रकार के संभावित प्रकार को रूप में रखने की अनुमति नहीं देता है

जैसा कि मैंने कहा था कि इसे सी ++ में कार्यान्वित किया जा सकता है, लेकिन भाषा और अच्छे इंटरफ़ेस डिज़ाइन के गहन ज्ञान की आवश्यकता होती है, ताकि उस वर्ग के उपयोगकर्ता आड़ू के रूप में सेब को संभाल न दें।

कृपया हेनरी स्पेंसर के शब्दों को याद रखें: यदि आप संकलक से झूठ बोलते हैं, तो उसका बदला मिलेगा।

सादर,

Ovanes


कार्यान्वयन का विचार (! Untested!)

 class any_type { class any_container { public: virtual ~any_container(){} virtual void* pointer()=0; virtual type_info const& get_type()const=0; }; template<class T> class any_container_impl { T t_; public: any_container_impl(T const& t) : t_(t) {} virtual ~any_container_impl(){} virtual void* pointer() { return &t_; } virtual type_info const& get_type()const { return typeid(T); } }; std::auto_ptr<any_container> content_; public: template<class T> any_type(T const& t) : content_(new any_container_impl<T>(t)) {} template<class T> T* cast_to_ptr() { if(typeid(T)!=content_->get_type()) return NULL; return reinterpret_cast<T*>(content_->pointer()); } template<class T> T& cast_to_ref() { T* ptr = cast_to_ptr<T>(); if(!ptr) throw std::logic_error("wrong type"); return *ptr; } }; 

आप सही हैं कि कंपाइलर आसानी से अनुमान लगा सकता है, लेकिन यह मानक या C ++ 0x में नहीं है, जहां तक ​​मुझे पता है, आपको कम से कम 10 और साल (आईएसओ मानकों को चारों ओर मोड़ने की दर) इंतजार करना होगा इससे पहले कि कंपाइलर प्रदाता इस सुविधा को जोड़ते हैं

चलो एक वर्ग के संदर्भ में समस्या को देखते हुए सभी के साथ famild होना चाहिए – std :: vector

सबसे पहले, वेक्टर का एक बहुत ही सामान्य उपयोग कंस्ट्रक्टर का उपयोग करना है जो कोई पैरामीटर नहीं लेता है:

 vector <int> v; 

इस मामले में, स्पष्ट रूप से कोई निष्कर्ष नहीं किया जा सकता है।

एक दूसरा आम उपयोग एक पूर्व-आकार वाले वेक्टर बनाने के लिए है:

 vector <string> v(100); 

यहां, यदि अनुमान प्रयोग किया जाता है:

 vector v(100); 

हम ints के एक वेक्टर प्राप्त करते हैं, तार नहीं, और शायद यह आकार नहीं है!

अन्त में, "निष्कर्ष" के साथ कई मापदंडों लेने वाले कंस्ट्रक्चर पर विचार करें:

 vector v( 100, foobar() ); // foobar is some class 

अनुमान के लिए कौन सी पैरामीटर का उपयोग किया जाना चाहिए? हमें कंपाइलर को यह कहने के कुछ तरीके की आवश्यकता होगी कि यह दूसरा वाला होना चाहिए।

वेक्टर के रूप में सरल रूप से एक कक्षा के लिए इन सभी समस्याओं के साथ, यह देखना आसान है कि अनुमान का उपयोग क्यों नहीं किया जाता है।

सीटीओआर को एक टेम्पलेट बनाना वैरिएबल का केवल एक ही रूप हो सकता है लेकिन विभिन्न सीटीओर्स:

 class Variable { obj data; // let the compiler guess public: template<typename obj> Variable(obj d) { data = d; } }; int main() { int num = 2; Variable var(num); // Variable::data int? float num2 = 2.0f; Variable var2(num2); // Variable::data float? return 0; } 

देख? हमारे पास कई वैरिएबल :: डेटा सदस्य नहीं हो सकते।

इस पर अधिक जानकारी के लिए सी ++ खाका दलील कटौती देखें।