परिचय: C++ में Generics क्या हैं और वे क्यों आवश्यक हैं?
प्रोग्रामिंग की दुनिया में अक्सर ऐसा कोड लिखने की आवश्यकता होती है जो विभिन्न डेटा प्रकारों के साथ समान रूप से अच्छी तरह से काम करे। उदाहरण के लिए, एक ऐरे को सॉर्ट करने वाला फंक्शन पूर्णांकों, स्ट्रिंग्स या उपयोगकर्ता-परिभाषित ऑब्जेक्ट्स को सॉर्ट करने में सक्षम होना चाहिए। सामान्यीकृत प्रोग्रामिंग (generics) के तंत्र के बिना, प्रत्येक प्रकार के लिए अलग-अलग फंक्शन लिखने होंगे, जिससे कोड की पुनरावृत्ति, त्रुटियाँ और रखरखाव में जटिलता बढ़ती है।
C++ में यह समस्या टेम्पलेट्स (templates) द्वारा हल की जाती है — एक शक्तिशाली उपकरण जो सामान्यीकृत फंक्शन और क्लास बनाने की अनुमति देता है। C++ में generics की अवधारणा टेम्पलेट्स के माध्यम से लागू की गई है। ये प्रोग्रामर को किसी विशिष्ट प्रकार से बंधे बिना एल्गोरिदम या डेटा संरचना को परिभाषित करने की अनुमति देते हैं, और प्रकार को संकलन चरण में प्रतिस्थापित किया जाता है।
टेम्पलेट्स के उपयोग के मुख्य लाभ:
- कोड पुनरावृत्ति में कमी — एक टेम्पलेट कई ओवरलोडेड फंक्शन को बदल देता है।
- प्रकार सुरक्षा — सभी प्रकार की जाँच संकलन चरण में की जाती है।
- प्रदर्शन — टेम्पलेट्स रनटाइम पर कोई अतिरिक्त ओवरहेड नहीं जोड़ते, क्योंकि कोड प्रत्येक विशिष्ट प्रकार के लिए अलग-अलग उत्पन्न होता है।
- लचीलापन — जटिल सामान्यीकृत संरचनाएँ बनाई जा सकती हैं, जिनमें कंटेनर (STL) और एल्गोरिदम शामिल हैं।
इस लेख में, हम विस्तार से समझेंगे कि C++ में टेम्पलेट्स का उपयोग कैसे करें, सरल उदाहरणों से शुरू करके उन्नत तकनीकों तक।
फंक्शन टेम्पलेट्स के साथ काम करने की मूल बातें
Generics से परिचित होने का सबसे सरल तरीका एक टेम्पलेट फंक्शन लिखना है। मान लीजिए, हमें एक फंक्शन चाहिए जो दो मानों में से अधिकतम खोजे। टेम्पलेट्स के बिना, हमें int, double, std::string आदि के लिए ओवरलोड लिखने होंगे। टेम्पलेट्स के साथ, यह एक बार किया जाता है:
#include <iostream>#include <string>
// फंक्शन टेम्पलेटtemplate <typename T>T max(T a, T b) { return (a > b) ? a : b;}
int main() { std::cout << max(10, 20) << std::endl; // int std::cout << max(3.14, 2.71) << std::endl; // double std::cout << max("apple", "orange") << std::endl; // const char* (स्ट्रिंग तुलना) return 0;}यहाँ कीवर्ड template एक टेम्पलेट घोषित करता है, और typename T (या class T) प्रकार पैरामीटर निर्दिष्ट करता है। कंपाइलर स्वचालित रूप से प्रत्येक उपयोग किए गए प्रकार के लिए फंक्शन का संस्करण उत्पन्न करता है। यह ध्यान रखना महत्वपूर्ण है कि प्रकारों को ऑपरेटर > का समर्थन करना चाहिए — अन्यथा संकलन त्रुटि होगी।
आप कई प्रकार के पैरामीटर भी निर्दिष्ट कर सकते हैं:
template <typename T1, typename T2>void printPair(T1 a, T2 b) { std::cout << "(" << a << ", " << b << ")" << std::endl;}
// उपयोगprintPair(42, "Hello"); // (42, Hello)क्लास टेम्पलेट्स: सार्वभौमिक कंटेनर बनाना
क्लास टेम्पलेट्स सामान्यीकृत डेटा संरचनाएँ बनाने की अनुमति देते हैं — यह स्टैंडर्ड टेम्पलेट लाइब्रेरी (STL) का आधार है। आइए डायनामिक ऐरे के लिए एक सरल टेम्पलेट क्लास का उदाहरण देखें:
#include <iostream>#include <stdexcept>
template <typename T>class Array {private: T* data; size_t size;public: Array(size_t sz) : size(sz) { data = new T[size]; } ~Array() { delete[] data; } T& operator[](size_t index) { if (index >= size) { throw std::out_of_range("Index out of range"); } return data[index]; } size_t getSize() const { return size; }};
int main() { Array<int> intArray(5); // पूर्णांकों का ऐरे Array<double> doubleArray(3); // दशमलव संख्याओं का ऐरे