2013-06-04 18 views
7

के अंदर स्थिर सदस्य फ़ंक्शन क्लास टेम्पलेट के अंदर परिभाषित स्थिर सदस्य फ़ंक्शन तक पहुंचने के लिए संघर्ष कर रहा हूं। हेडर फाइल TemplateTest.h में मैं के रूप में प्राथमिक वर्ग खाका परिभाषित:क्लास टेम्पलेट विशेषज्ञता

#include<iostream> 

template<class T, class U> 
struct TemplateTest 
{ 
public: 
    void static invoke(); 
    /*{ 

     std::cout << "Should not be called" << std::endl; 

    }*/ 
}; 

तो स्रोत फ़ाइल TemplateTester.cpp मैं एक विशेषज्ञता डाल:

#include "TemplateTest.h" 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

template struct TemplateTest<int, bool>; //instantiate to resolve linker issue 

मैं स्पष्ट रूप से ऐसा लिंकर निराकरण के साथ वर्ग instantiated सही ढंग से।

ड्राइवर driver.cpp में:

include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
    return 0; 
} 

जब मैं जी के साथ TemplateTest.cpp संकलन ++ यह वस्तु फ़ाइल ठीक से उत्पन्न करता है लेकिन जब मैं ड्राइवर वर्ग से लिंक करने की कोशिश यह मेरी लिंकर त्रुटि "देता है `टेम्पलेटटेस्ट :: invoke()"

के लिए अनिर्धारित संदर्भ मैं this one जैसे अन्य संबंधित पोस्टिंग के माध्यम से गया लेकिन मैं फ़ंक्शन टेम्पलेट तक पहुंचने का प्रयास नहीं कर रहा हूं।

कोई सुराग बहुत सराहना की है।

+4

कार्यान्वयन को हेडर फ़ाइल में ले जाएं। टेम्पलेट के कार्यान्वयन को उन सभी टीयू के लिए दृश्यमान होने की आवश्यकता है। –

उत्तर

5

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

हालांकि, उस समय जब driver.cpp संकलित किया गया है, तो कंपाइलर को विशेषज्ञता के बारे में पता नहीं है, क्योंकि आप केवल TemplateTester.h शामिल हैं, और विशेषज्ञता का उल्लेख नहीं किया गया है। तो संकलक टेम्पलेट को तत्काल परिभाषा का उपयोग नहीं करता है, इसलिए आपको अपनी समस्या मिलती है।

(§14.7:

मानक (मेरे द्वारा तिरछे) कहते हैं।3/6) यदि कोई टेम्पलेट, एक सदस्य टेम्पलेट या क्लास टेम्पलेट का सदस्य स्पष्ट रूप से विशिष्ट है तो उस विशेषज्ञता के पहले उपयोग से पहले विशेषज्ञता घोषित की जाएगी जो एक अंतर्निहित तत्कालता का कारण बन जाएगी, प्रत्येक अनुवाद इकाई में जो इस तरह का उपयोग होता है; कोई निदान की आवश्यकता नहीं है। यदि कार्यक्रम एक स्पष्ट विशेषज्ञता के लिए परिभाषा प्रदान नहीं करता है और या तो विशेषज्ञता का उपयोग ऐसे तरीके से किया जाता है जो एक निहित तत्कालता का कारण बनता है या सदस्य आभासी सदस्य कार्य होता है, तो कार्यक्रम खराब हो जाता है, कोई निदान आवश्यक नहीं होता है। एक स्पष्ट तत्कालता कभी स्पष्ट स्पष्टीकरण के लिए उत्पन्न नहीं होती है जिसे घोषित किया जाता है लेकिन परिभाषित नहीं किया जाता है। [...]

तो तुम दोनों बनाने की जरूरत है, घोषणा और संकलक के लिए जाना जाता है, जब यह driver.cpp पर काम करता है विशेषज्ञता की परिभाषा। ऐसा करने का सबसे अच्छा तरीका संपूर्ण विशेषज्ञता को TemplateTester.h पर जोड़ना है।

नोट, फिर से, एक स्पष्ट तत्काल आवश्यकता वास्तव में आवश्यक नहीं है।

+1

स्पष्टीकरण @jogojapan के लिए धन्यवाद। यह वास्तव में टेम्पलेट स्थैतिक पुस्तकालय का एक प्रोटोटाइप है जिस पर मैं काम कर रहा हूं। अब मैं देख सकता हूं कि यह क्यों विफल रहा है मुझे लगता है कि मैं संकलक को खुश रखने के लिए परिभाषाओं को स्थानांतरित कर सकता हूं। – jazaman

3

कई समस्याएं हैं:

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

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 
template<> 
struct TemplateTest<int, bool> 
{ 
    inline static void invoke() 
    { 
     std::cout << "invoke<int, bool>" << std::endl; 
    } 
}; 

// main.cpp 
include "TemplateTest.h" 

int main() 
{ 
    TemplateTest<int, bool>::invoke(); 
} 

एक और तरीका है हेडर बदलने के लिए, और स्रोत फ़ाइल जोड़ना है।

// TemplateTest.h 
#include<iostream> 

template<class T, class U> 
struct TemplateTest; 

template<> 
struct TemplateTest<int, bool> 
{ 
    static void invoke(); 
}; 

// TemplateTest.cpp 
#include "TemplateTest.h" 
void TemplateTest<int, bool>::invoke() 
{ 
    std::cout << "invoke<int, bool>" << std::endl; 
} 
+0

धन्यवाद @ BЈовић मैंने वास्तव में यहां एक प्रोटोटाइप के साथ आने की कोशिश की। हो सकता है कि मुझे स्पष्ट रूप से उनका उल्लेख किया जाना चाहिए। कक्षा टेम्पलेट वास्तव में एक स्थिर पुस्तकालय का हिस्सा हैं और इसलिए, मुझे लगता है कि मुझे अभी भी तत्काल आवश्यकता होगी। लेकिन आप सही हैं मुझे कक्षा के अंदर समारोह को परिभाषित नहीं करना चाहिए। यह बाहर किया जाना चाहिए। मैं कोशिश करूँगा और देख सकता हूं कि यह मेरी समस्या का समाधान करता है या नहीं। – jazaman

+0

@jazaman नहीं, आपको पूरी तरह से विशिष्ट टेम्पलेट्स को तुरंत चालू करने की आवश्यकता नहीं है, क्योंकि वे सामान्य (गैर-टेम्पलेट) कक्षाओं की तरह हैं। यदि आप अपने शीर्षलेख को कई स्थानों पर शामिल करते हैं, तो आपको लिंकर त्रुटियां मिलेंगी। अन्य उत्तर पढ़ने के बाद –

+0

मैं समझता हूं कि अगर यह पूरी तरह से विशिष्ट मामला है तो इसे और करने की आवश्यकता नहीं है। – jazaman

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