2009-08-30 18 views
24

मुझे एक टेम्पलेट क्लास को कॉल करने में कोई समस्या है। मैंने एक नया प्रकार नाम ऐरे घोषित किया, जो एक टेम्पलेट है;सी ++ टेम्पलेट, त्रुटि

.hpp फ़ाइल में:

template <typename T> 
class Array 
{ 
public: 
    Array(); 
}; 

.cpp फ़ाइल में:

template <typename T> 
Array<T>::Array() 
{ 
//Do something 
} 

मुख्य में:

Array<int> arr; 

मैं लिंकेज त्रुटि मिलती है: करने के लिए अनसुलझे बाह्य प्रतीक ctor।

कोई विचार?

+0

इस प्रश्न को https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file पर लिंक करना उपयोगी है लेकिन यह वास्तव में एक डुप्लिकेट नहीं है। ओपी को ऐसा कुछ नहीं पता था जो पूरी तरह से उस प्रश्न में माना गया था। – Winter

उत्तर

47

सदस्य फ़ंक्शंस सहित टेम्पलेट फ़ंक्शंस पूरी तरह से शीर्षलेखों में लिखे जाने चाहिए। इसका मतलब है कि यदि आपके पास टेम्पलेट वर्ग है, तो इसका कार्यान्वयन पूरी तरह से शीर्षलेख में होना चाहिए। ऐसा इसलिए है क्योंकि टेम्पलेट के प्रत्येक तत्कालता के लिए कोड उत्पन्न करने के लिए संकलक को संपूर्ण टेम्पलेट परिभाषा (केवल हस्ताक्षर नहीं) तक पहुंच की आवश्यकता होती है।

+0

हाँ यह काम किया। क्या आप कृपया अधिक स्पष्टीकरण जोड़ सकते हैं कि आपको हेडर में इसे सभी को परिभाषित करने की आवश्यकता क्यों है? इसके अलावा मैंने जो कार्यान्वयन जोड़ा, मैंने "एंडिफ़" से पहले सभी को जोड़ा, है ना? –

+1

सही। क्यों एक अच्छा स्पष्टीकरण के लिए, देखें http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12 और निम्न प्रश्न 35.13 जो कि चंद्रमा से जुड़ा हुआ है। –

+7

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

8

हेडर फ़ाइल में दोनों टेम्पलेट घोषणा और टेम्पलेट फ़ंक्शन परिभाषाएं रखें। अधिकांश सी ++ कंपाइलर्स टेम्पलेट्स के लिए अलग संकलन मॉडल का आसानी से समर्थन नहीं करते हैं,

6

यदि किसी टेम्पलेटेड फ़ंक्शन की परिभाषा उस बिंदु पर दिखाई नहीं दे रही है जहां इसका उपयोग किया जाता है (यानी हेडर या एक ही सीपीपी फ़ाइल में नहीं है), तो आपको tell the compiler which instantiations to make की आवश्यकता है।

3

आपके पास यहां की समस्या यह है कि आपने .cpp फ़ाइल में कन्स्ट्रक्टर की परिभाषा को छुपाया है। यह परिभाषा पर सभी प्रकार T, T सहित int के रूप में लागू होती है, लेकिन वास्तव में कोई परिभाषा नहीं देती है क्योंकि यह अभी भी केवल एक घोषणा है।
लिंकर Array<int>::Array() प्रतीक नहीं ढूंढ सकता है। अपने Array.cpp फ़ाइल के अंत तक

Array<int> arr1; 

और इस संकलक इन्स्तांत सही परिभाषा है कि लिंकर की तलाश में है बनाता है:

अब आप इस तरह की एक पंक्ति जोड़ सकते हैं। हालांकि, यह केवल एक परिभाषा की आपूर्ति करता है, Array<int> और कोई अन्य नहीं।

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

Array<double> arr2; 

अपने Array.cpp फ़ाइल के अंत में - अब आप देख सकते हैं कि यह कैसे असुरक्षित है!

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

0

ऊपर वर्णित अनुसार, सी ++ में टेम्पलेट्स में संकलन समय पर संकलक द्वारा नई विधियों की प्रक्रिया निष्पादित की जा रही है, समस्या यह है कि उस समय के दौरान थॉम की सभी परिभाषाओं को जानना आवश्यक है, इसलिए सभी वर्ग/कार्य घोषणा होना चाहिए आर एच या एचपीपी फाइलें।

1

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

संबंधित मुद्दे