दिलचस्प पोस्ट
इकाई फ़्रेमवर्क 4 .NET में एक इकाई को कैसे अपडेट करें खोज परिणाम नहीं मिला अगर "नल" ऑब्जेक्ट लौटें मूल कक्षा से बाल वर्ग में कास्ट करने में असमर्थ सी # में सेलेनियम वेबड्राइवर का उपयोग करके जावास्क्रिप्ट निष्पादित करें सी और सी ++: स्वत: संरचना का आंशिक प्रारंभ जावास्क्रिप्ट में स्प्रेड ऑपरेटर का कई बार उपयोग करना? पायथन में मल्टी प्रसंस्करण का उपयोग करते समय मुझे कैसे लॉग करना चाहिए? एक जावा अनुप्रयोग रिमोट डीबगिंग स्क्रॉलिंग के बाद तत्व दिखाई देने पर देखें एंड्रॉइड स्टूडियो में लाइब्रेरी को हल करने में श्रेय विफल रहा चेतावनी: समारोह का अंतर्निहित घोषणा सी + + स्थिर सदस्य चर और इसके आरंभीकरण विधि कॉल से पहले अपनी प्रारंभिक अवस्था में प्राथमिकता क्यूई को कैसे पुनर्स्थापित करना है? क्या ईवेंट डिस्पैच थ्रेड पर स्विंग / एडब्ल्यूटी विजेट्स का निर्माण सुरक्षित है? इंटरनेट से XAMPP लोकलहोस्ट तक पहुंचें

टेम्पलेट टेम्पलेट पैरामीटर के कुछ उपयोग सी ++ में क्या हैं?

मैंने टेम्पलेट टेम्पलेट पैरामीटर का उपयोग करते हुए सी + + के कुछ उदाहरणों को देखा है (जो कि टेम्प्लेट है जो पैरामीटर के रूप में टेम्प्लेट लेता है) नीति-आधारित क्लास डिज़ाइन करने के लिए। इस तकनीक का क्या अन्य उपयोग करता है?

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

मुझे लगता है कि आपको टेम्प्लेट टेम्पलेट सिंटैक्स का उपयोग करने के लिए एक पैरामीटर पास करने की आवश्यकता है जिसका प्रकार एक टेम्पलेट पर निर्भर है जैसे कि किसी अन्य टेम्पलेट पर:

template <template<class> class H, class S> void f(const H<S> &value) { } 

यहां, H एक टेम्पलेट है, लेकिन मैं यह समारोह H सभी विशेषज्ञताओं से निपटने के लिए चाहता था।

नोट : मैं कई सालों से प्रोग्रामिंग कर रहा हूं और केवल एक बार इसे करने की आवश्यकता है। मुझे लगता है कि यह शायद ही कभी आवश्यक सुविधा है (निश्चित रूप से जब आपको इसकी आवश्यकता होती है!)।

मैं अच्छे उदाहरणों के बारे में सोचने की कोशिश कर रहा हूं, और ईमानदारी से, ज़्यादातर समय यह आवश्यक नहीं है, लेकिन हम एक उदाहरण का पालन करते हैं। चलो दिखाते हैं कि std::vector में typedef value_type नहीं है

तो आप एक समारोह कैसे लिखेंगे जो वैक्टर तत्वों के लिए सही प्रकार के चर बना सकते हैं? यह काम करेगा

 template <template<class, class> class V, class T, class A> void f(V<T, A> &v) { // This can be "typename V<T, A>::value_type", // but we are pretending we don't have it T temp = v.back(); v.pop_back(); // Do some work on temp std::cout << temp << std::endl; } 

नोट : हम std::vector के दो टेम्पलेट पैरामीटर, प्रकार और आवंटक हैं, इसलिए हमें उन दोनों को स्वीकार करना पड़ा। सौभाग्य से, प्रकार कटौती की वजह से, हमें स्पष्ट रूप से सटीक प्रकार लिखने की आवश्यकता नहीं होगी।

जो आप इस तरह से उपयोग कर सकते हैं:

 f<std::vector, int>(v); // v is of type std::vector<int> using any allocator 

या बेहतर अभी तक, हम बस का उपयोग कर सकते हैं:

 f(v); // everything is deduced, f can deal with a vector of any type! 

अद्यतन : यहां तक ​​कि इस उपेक्षित उदाहरण, उदाहरण के तौर पर, सी ++ 11 की शुरूआत auto कारण अब कोई आश्चर्यजनक उदाहरण नहीं है। अब एक ही समारोह के रूप में लिखा जा सकता है:

 template <class Cont> void f(Cont &v) { auto temp = v.back(); v.pop_back(); // Do some work on temp std::cout << temp << std::endl; } 

जो कि मैं इस प्रकार के कोड को लिखना पसंद करता हूं।

असल में, टेम्प्लेट टेम्पलेट पैरामीटर के लिए usecase बल्कि स्पष्ट है। एक बार जब आप सीखते हैं कि मानक कंटेनर प्रकारों के लिए स्ट्रीम आउटपुट ऑपरेटरों को परिभाषित नहीं करने के सी + + स्टैडीलिब में दूरी छेद है, तो आप ऐसा कुछ लिखना चाहते हैं:

 template<typename T> static inline std::ostream& operator<<(std::ostream& out, std::list<T> const& v) { out << '['; if (!v.empty()) { for (typename std::list<T>::const_iterator i = v.begin(); ;) { out << *i; if (++i == v.end()) break; out << ", "; } } out << ']'; return out; } 

फिर आप यह पता लगा सकते हैं कि वेक्टर के लिए कोड केवल वही है, फॉरवर्ड_लिस्ट समान है, वास्तव में, यहां तक ​​कि मानचित्र प्रकारों के लिए भी अभी भी यही है। उन टेम्पलेट वर्गों में मेटा-इंटरफ़ेस / प्रोटोकॉल और टेम्प्लेट टेम्पलेट पैरामीटर का उपयोग करने के अलावा सामान्य में कुछ भी नहीं है, उन सभी में समानता को कैप्चर करने की अनुमति है यद्यपि एक टेम्पलेट लिखने के लिए पहले, यह याद करने के लिए एक संदर्भ को देखने के लिए लायक है कि अनुक्रम कंटेनर 2 टेम्पलेट तर्क स्वीकार करते हैं – मूल्य प्रकार और आवंटन के लिए जबकि आबंटक चूक है, हमें अब भी अपने टेम्पलेट ऑपरेटर में अपने अस्तित्व के लिए खाते चाहिए <<:

 template<template <typename, typename> class Container, class V, class A> std::ostream& operator<<(std::ostream& out, Container<V, A> const& v) ... 

वोइला, जो मानक प्रोटोकॉल का पालन करने वाले सभी वर्तमान और भविष्य के अनुक्रम कंटेनरों के लिए स्वचालित रूप से काम करेगा। मिश्रण के लिए नक्शे जोड़ने के लिए, यह ध्यान देने के संदर्भ में एक झांक लगाएगा कि वे 4 टेम्पलेट पैरामीटर स्वीकार करते हैं, इसलिए हमें 4-एजी टेम्पलेट टेम्पलेट परम के साथ ऑपरेटर के दूसरे संस्करण की आवश्यकता होगी हम यह भी देखेंगे कि std: pair 2-arg ऑपरेटर के साथ प्रदान करने की कोशिश करता है << हम पूर्व में परिभाषित अनुक्रम प्रकारों के लिए, इसलिए हम std :: pair के लिए विशेष प्रदान करेंगे।

बीटीडब्लू, सी +11 के साथ, जो कि वैरायडिक टेम्पलेट्स को अनुमति देता है (और इस तरह से वैरायडिक टेम्प्लेट टेम्पलेट अरग्स को अनुमति देनी चाहिए), उन सभी को शासन करने के लिए एकल ऑपरेटर << होना संभव होगा उदाहरण के लिए:

 #include <iostream> #include <vector> #include <deque> #include <list> template<typename T, template<class,class...> class C, class... Args> std::ostream& operator <<(std::ostream& os, const C<T,Args...>& objs) { os << __PRETTY_FUNCTION__ << '\n'; for (auto const& obj : objs) os << obj << ' '; return os; } int main() { std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 }; std::cout << vf << '\n'; std::list<char> lc { 'a', 'b', 'c', 'd' }; std::cout << lc << '\n'; std::deque<int> di { 1, 2, 3, 4 }; std::cout << di << '\n'; return 0; } 

उत्पादन

 std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = float, C = vector, Args = <std::__1::allocator<float>>] 1.1 2.2 3.3 4.4 std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = char, C = list, Args = <std::__1::allocator<char>>] abcd std::ostream &operator<<(std::ostream &, const C<T, Args...> &) [T = int, C = deque, Args = <std::__1::allocator<int>>] 1 2 3 4 

आंद्रेई अलेक्जेंडरको द्वारा 'आधुनिक सी + + डिजाइन – जेनेरिक प्रोग्रामिंग और डिजाइन पैटर्न एप्लाइड' से लिया गया एक सरल उदाहरण है:

वह पॉलिसी पैटर्न को लागू करने के लिए टेम्प्लेट टेम्पलेट पैरामीटर के साथ एक कक्षा का उपयोग करता है:

 // Library code template <template <class> class CreationPolicy> class WidgetManager : public CreationPolicy<Widget> { ... }; 

वे बताते हैं: आमतौर पर, मेजबान वर्ग पहले से ही जानता है, या आसानी से निकाला जा सकता है, पॉलिसी कक्षा के टेम्पलेट तर्क। उपरोक्त उदाहरण में, विजेटमैन्गेर हमेशा प्रकार विजेट के ऑब्जेक्ट्स का प्रबंधन करता है, इसलिए क्रिएशन पॉलिसी के तत्काल में उपयोगकर्ता को फिर से विजेट को निर्दिष्ट करने की आवश्यकता होती है अनावश्यक और संभावित खतरनाक है। इस मामले में, लाइब्रेरी कोड नीतियों को निर्दिष्ट करने के लिए टेम्प्लेट टेम्पलेट पैरामीटर का उपयोग कर सकता है

प्रभाव यह है कि क्लाइंट कोड 'विजिटमैनेजर' का उपयोग अधिक सुंदर तरीके से कर सकता है:

 typedef WidgetManager<MyCreationPolicy> MyWidgetMgr; 

इसके बजाय अधिक जटिल, और त्रुटि प्रवण तरीका है कि परिभाषा टेम्पलेट टेम्पलेट तर्कों की कमी के लिए आवश्यक होगा:

 typedef WidgetManager< MyCreationPolicy<Widget> > MyWidgetMgr; 

मेरे CUDA Convolutional neural network library से यहाँ एक और व्यावहारिक उदाहरण है मेरे पास निम्न क्लास टेम्पलेट हैं:

 template <class T> class Tensor 

जो वास्तव में एन-आयामी मैट्रिक्स हेरफेर लागू करता है। वहाँ भी एक बच्चे वर्ग टेम्पलेट है:

 template <class T> class TensorGPU : public Tensor<T> 

जो एक ही कार्यक्षमता लागू करता है लेकिन GPU में दोनों टेम्पलेट सभी बुनियादी प्रकार, जैसे फ्लोट, डबल, इन्ट आदि के साथ काम कर सकते हैं और मेरे पास एक क्लास टेम्प्लेट (सरलीकृत) भी है:

 template <template <class> class TT, class T> class CLayerT: public Layer<TT<T> > { TT<T> weights; TT<T> inputs; TT<int> connection_matrix; } 

यहां टेम्पलेट टेम्पलेट सिंटैक्स के लिए कारण है क्योंकि मैं कक्षा के कार्यान्वयन की घोषणा कर सकता हूं

 class CLayerCuda: public CLayerT<TensorGPU, float> 

जो कि दोनों भार और टाइप फ़्लोट और जीपीयू पर इनपुट होंगे, लेकिन connection_matrix हमेशा सीपीयू (टीटी = निविदा निर्दिष्ट करके) या जीपीयू (टीटी = TensorGPU निर्दिष्ट करके) पर होगा।

कहते हैं कि आप बाल टेम्पलेट के सेट के लिए "इंटरफ़ेस" प्रदान करने के लिए CRTP का उपयोग कर रहे हैं; और माता-पिता और बच्चे दोनों ही दूसरे टेम्पलेट तर्कों में पैरामीट्रिक हैं:

 template <typename DERIVED, typename VALUE> class interface { void do_something(VALUE v) { static_cast<DERIVED*>(this)->do_something(v); } }; template <typename VALUE> class derived : public interface<derived, VALUE> { void do_something(VALUE v) { ... } }; typedef interface<derived<int>, int> derived_t; 

'इंट' के दोहराव पर ध्यान दें, जो वास्तव में एक ही प्रकार का पैरामीटर है जो दोनों टेम्पलेट्स के लिए निर्दिष्ट है। इस दोहराव से बचने के लिए आप DERIVED के लिए टेम्पलेट टेम्पलेट का उपयोग कर सकते हैं:

 template <template <typename> class DERIVED, typename VALUE> class interface { void do_something(VALUE v) { static_cast<DERIVED<VALUE>*>(this)->do_something(v); } }; template <typename VALUE> class derived : public interface<derived, VALUE> { void do_something(VALUE v) { ... } }; typedef interface<derived, int> derived_t; 

ध्यान दें कि आप सीधे दूसरे टेम्प्लेट पैरामीटर को व्युत्पन्न टेम्पलेट को प्रदान कर रहे हैं; "अंतरफलक" अभी भी उन्हें प्राप्त करता है

यह आपको "इंटरफ़ेस" में टाइप-फेफ्स बनाने की भी सुविधा देता है जो कि प्रकार पैरामीटर पर निर्भर करता है, जो व्युत्पन्न टेम्पलेट से पहुंच योग्य होगा।

उपरोक्त typedef काम नहीं करता है क्योंकि आप एक अनिर्दिष्ट टेम्पलेट के लिए टाइप नहीं कर सकते यह काम करता है, हालांकि (और सी + + 11 टेम्पलेट टाइपिंग के लिए मूल समर्थन है):

 template <typename VALUE> struct derived_interface_type { typedef typename interface<derived, VALUE> type; }; typedef typename derived_interface_type<int>::type derived_t; 

दुर्भाग्य से व्युत्पन्न टेम्पलेट के प्रत्येक तत्काल के लिए आपको एक derived_interface_type की आवश्यकता है, जब तक कि मैं अभी तक नहीं सीखा है एक और चाल है।

यह वही है जो मैं चला गया:

 template<class A> class B { A& a; }; template<class B> class A { B b; }; class AInstance : A<B<A<B<A<B<A<B<... (oh oh)>>>>>>>> { }; 

इसका समाधान किया जा सकता है:

 template<class A> class B { A& a; }; template< template<class> class B> class A { B<A> b; }; class AInstance : A<B> //happy { }; 

या (काम कर रहे कोड):

 template<class A> class B { public: A* a; int GetInt() { return a->dummy; } }; template< template<class> class B> class A { public: A() : dummy(3) { ba = this; } B<A> b; int dummy; }; class AInstance : public A<B> //happy { public: void Print() { std::cout << b.GetInt(); } }; int main() { std::cout << "hello"; AInstance test; test.Print(); } 

फ़्लिकोन द्वारा प्रदान किए गए वैरायडिक टेम्पलेट्स के समाधान के साथ, मुझे यह पता चला कि वास्तविकता के लालची प्रकृति के कारण वास्तव में ओस्ट्रीम ऑपरेटर के लिए std :: नक्शा के विशेषज्ञ हैं। यहाँ एक मामूली संशोधन है जो मेरे लिए काम करता है:

 #include <iostream> #include <vector> #include <deque> #include <list> #include <map> namespace containerdisplay { template<typename T, template<class,class...> class C, class... Args> std::ostream& operator <<(std::ostream& os, const C<T,Args...>& objs) { std::cout << __PRETTY_FUNCTION__ << '\n'; for (auto const& obj : objs) os << obj << ' '; return os; } } template< typename K, typename V> std::ostream& operator << ( std::ostream& os, const std::map< K, V > & objs ) { std::cout << __PRETTY_FUNCTION__ << '\n'; for( auto& obj : objs ) { os << obj.first << ": " << obj.second << std::endl; } return os; } int main() { { using namespace containerdisplay; std::vector<float> vf { 1.1, 2.2, 3.3, 4.4 }; std::cout << vf << '\n'; std::list<char> lc { 'a', 'b', 'c', 'd' }; std::cout << lc << '\n'; std::deque<int> di { 1, 2, 3, 4 }; std::cout << di << '\n'; } std::map< std::string, std::string > m1 { { "foo", "bar" }, { "baz", "boo" } }; std::cout << m1 << std::endl; return 0; } 

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

 #include <vector> template <class T> class Alloc final { /*...*/ }; template <template <class T> class allocator=Alloc> class MyClass final { public: std::vector<short,allocator<short>> field0; std::vector<float,allocator<float>> field1; }; 

यह आपके कोड की पठनीयता में सुधार करता है, अतिरिक्त प्रकार की सुरक्षा प्रदान करता है और कुछ संकलक प्रयासों को बचाता है।

कहते हैं कि आप प्रत्येक कंटेनर के प्रत्येक तत्व को मुद्रित करना चाहते हैं, तो आप टेम्पलेट टेम्पलेट पैरामीटर के बिना निम्न कोड का उपयोग कर सकते हैं

 template <typename T> void print_container(const T& c) { for (const auto& v : c) { std::cout << v << ' '; } std::cout << '\n'; } 

या टेम्पलेट टेम्पलेट पैरामीटर के साथ

 template< template<typename, typename> class ContainerType, typename ValueType, typename AllocType> void print_container(const ContainerType<ValueType, AllocType>& c) { for (const auto& v : c) { std::cout << v << ' '; } std::cout << '\n'; } 

मान लें कि आप एक पूर्णांक में पारित करते हैं, print_container(3) पूर्व मामले के लिए, टेम्पलेट कंपाइलर द्वारा इंस्टीटिव किया जाएगा जो कि लूप में c के उपयोग के बारे में शिकायत करेगा, बाद वाला टेम्पलेट बिल्कुल भी इन्स्तांत नहीं करेगा क्योंकि कोई मिलान प्रकार नहीं पाया जा सकता है।

आम तौर पर, यदि आपका टेम्पलेट क्लास / फंक्शन टेम्पलेट क्लास को टेम्पलेट पैरामीटर के रूप में प्रबंधित करने के लिए डिज़ाइन किया गया है, तो इसे स्पष्ट करना बेहतर होगा।