जेनेरिक (या बल्कि: पैरामीट्रिक बहुरूपता) के अधिकांश कार्यान्वयन प्रकार के क्षरण का उपयोग करते हैं। यह सामान्य कोड को संकलित करने की समस्या को बहुत सरल करता है, लेकिन केवल बॉक्स प्रकारों के लिए काम करता है: चूंकि प्रत्येक तर्क प्रभावी रूप से एक अपारदर्शी सूचक है, हमें तर्कों पर संचालन करने के लिए एक VTable या समान प्रेषण तंत्र की आवश्यकता होती है। जावा में:
<T extends Addable> T add(T a, T b) { … }
संकलित किया जा सकता है, टाइप-चेक किया गया है, और उसी तरह से बुलाया जा सकता है
Addable add(Addable a, Addable b) { … }
सिवाय इसके कि जेनेरिक कॉल साइट पर अधिक जानकारी के साथ टाइप चेकर प्रदान करते हैं। यह अतिरिक्त जानकारी प्रकार चर के साथ संभाला जा सकता है , खासकर जब सामान्य प्रकार का अनुमान लगाया जाता है। जाँच के दौरान, प्रत्येक सामान्य प्रकार को एक चर के साथ बदला जा सकता है, आइए इसे कॉल करें $T1
:
$T1 add($T1 a, $T1 b)
प्रकार चर को तब अधिक तथ्यों के साथ अद्यतन किया जाता है जब तक कि वे ज्ञात नहीं हो जाते हैं, जब तक कि इसे एक ठोस प्रकार से प्रतिस्थापित नहीं किया जा सकता है। प्रकार की जाँच एल्गोरिथ्म को इस तरह से लिखा जाना चाहिए जो इन प्रकार के चर को समायोजित करता है, भले ही वे अभी तक पूर्ण प्रकार से हल न हों। जावा में यह आमतौर पर आसानी से किया जा सकता है क्योंकि प्रकार के तर्कों को अक्सर फ़ंक्शन कॉल के प्रकार से पहले जाना जाता है। एक उल्लेखनीय अपवाद फ़ंक्शन तर्क के रूप में एक लंबोदर अभिव्यक्ति है, जिसे इस प्रकार के चर के उपयोग की आवश्यकता होती है।
बहुत बाद में, एक ऑप्टिमाइज़र निश्चित संख्या के तर्कों के लिए विशेष कोड उत्पन्न कर सकता है, फिर यह प्रभावी रूप से एक प्रकार की इनलाइनिंग होगी।
जेनेरिक-टाइप किए गए तर्कों के लिए एक VTable से बचा जा सकता है यदि जेनेरिक फ़ंक्शन प्रकार पर कोई कार्रवाई नहीं करता है, लेकिन केवल उन्हें किसी अन्य फ़ंक्शन में भेजता है। उदाहरण के लिए हास्केल फ़ंक्शन call :: (a -> b) -> a -> b; call f x = f x
को x
तर्क को बॉक्स में नहीं रखना होगा । हालांकि, इसके लिए एक कॉलिंग कन्वेंशन की आवश्यकता होती है, जो उनके आकार को जाने बिना मानों से गुजर सकता है, जो अनिवार्य रूप से वैसे भी संकेत करने के लिए प्रतिबंधित करता है।
इस संदर्भ में C ++ अधिकांश भाषाओं से बहुत अलग है। एक टेम्प्लेटेड क्लास या फंक्शन (मैं यहाँ केवल टेम्पल किए गए फंक्शन की चर्चा करूँगा) अपने आप में कॉल करने योग्य नहीं है। इसके बजाय, टेम्पलेट्स को एक संकलन-समय मेटा-फ़ंक्शन के रूप में समझा जाना चाहिए जो एक वास्तविक फ़ंक्शन देता है। एक पल के लिए टेम्पलेट तर्क की अनदेखी, सामान्य दृष्टिकोण फिर इन चरणों के लिए उबालता है:
दिए गए टेम्प्लेट तर्कों पर टेम्पलेट लागू करें। उदाहरण के लिए बुला template<class T> T add(T a, T b) { … }
के रूप में add<int>(1, 2)
हमें वास्तविक समारोह देना होगा int __add__T_int(int a, int b)
(या जो भी नाम-mangling दृष्टिकोण प्रयोग किया जाता है)।
यदि उस फ़ंक्शन के लिए कोड वर्तमान संकलन इकाई में पहले से ही उत्पन्न हो गया है, तो जारी रखें। अन्यथा, कोड उत्पन्न करें जैसे कि कोई फ़ंक्शन int __add__T_int(int a, int b) { … }
स्रोत कोड में लिखा गया था। इसमें टेम्प्लेट तर्क की सभी घटनाओं को इसके मूल्यों के साथ बदलना शामिल है। यह संभवतः एएसटी → एएसटी परिवर्तन है। फिर, उत्पन्न एएसटी पर टाइप चेकिंग करें।
कॉल को ऐसे संकलित करें जैसे कि स्रोत कोड था __add__T_int(1, 2)
।
ध्यान दें कि C ++ टेम्प्लेट में ओवरलोड रिज़ॉल्यूशन तंत्र के साथ एक जटिल इंटरैक्शन होता है, जिसे मैं यहां वर्णन नहीं करना चाहता। यह भी ध्यान दें कि यह कोड-जेनरेशन एक टेम्प्लेटेड पद्धति को भी असंभव बना देता है जो आभासी भी है - एक प्रकार-इरेज़र आधारित दृष्टिकोण इस पर्याप्त प्रतिबंध से ग्रस्त नहीं है।
आपके कंपाइलर और / या भाषा के लिए इसका क्या अर्थ है? आप जिस तरह की जेनरिक पेशकश करना चाहते हैं, उसके बारे में आपको ध्यान से सोचना होगा। यदि आप बॉक्सिंग प्रकारों का समर्थन करते हैं, तो टाइप इंट्रेंस की अनुपस्थिति में टाइप इरेक्शन सबसे सरल संभव तरीका है। टेम्प्लेट विशेषज्ञता काफी सरल लगती है, लेकिन आम तौर पर आउटपुट में नाम जुड़ना और (कई संकलन इकाइयों के लिए) में पर्याप्त दोहराव शामिल होता है, क्योंकि टेम्प्लेट को कॉल साइट पर त्वरित किया जाता है, न कि परिभाषा साइट पर।
आपके द्वारा दिखाया गया दृष्टिकोण अनिवार्य रूप से C ++ है - जैसे टेम्पलेट दृष्टिकोण। हालाँकि, आप विशेष / तात्कालिक टेम्पलेट्स को मुख्य टेम्पलेट के "संस्करण" के रूप में संग्रहीत करते हैं। यह भ्रामक है: वे समान रूप से वैचारिक नहीं हैं, और किसी फ़ंक्शन के विभिन्न इंस्टेंसेस में बेतहाशा भिन्न प्रकार हो सकते हैं। यह लंबे समय में चीजों को जटिल करेगा यदि आप फ़ंक्शन को ओवरलोडिंग की अनुमति देते हैं। इसके बजाय, आपको एक अधिभार सेट की धारणा की आवश्यकता होगी जिसमें एक नाम साझा करने वाले सभी संभावित फ़ंक्शन और टेम्पलेट शामिल हों। ओवरलोडिंग को हल करने के अलावा, आप विभिन्न तात्कालिक टेम्पलेट्स पर विचार कर सकते हैं जो एक दूसरे से पूरी तरह से अलग हैं।