2012-11-12 43 views
6

मैं वाकिफ हूँ एक शीर्षक में एक टेम्पलेट वर्ग विधि की घोषणा और एक स्रोत फ़ाइल में यह परिभाषित करने के लिए वाक्य रचना के रूप में तो चला जाता है कि:सी ++ - टेम्पलेट कक्षा में टेम्पलेट समारोह के लिए अलग घोषणा/परिभाषा

myclass.h

template <typename T> 
class MyClass { 
    public: 
    void method(T input); 
    private: 
    T privVar; 
}; 

myclass.cpp

template <typename T> 
void MyClass<T>::method(T input) { 
    privVar = input; 
} 

लेकिन, क्या हुआ अगर विधि भी एक टेम्पलेट है? मैं basic_string कक्षा में विधियों को जोड़ रहा हूं, और मैं जानना चाहता हूं कि कार्यों के लिए कार्यान्वयन कैसे लिखना है।

MyString.h

template <class _Elem = TCHAR, 
      class _Traits = std::char_traits<_Elem>, 
      class _Ax  = std::allocator<_Elem>> 
class String 
    : public std::basic_string<_Elem, _Traits, _Ax> { 
    private: 
    // Types for the conversion operators. 
    typedef  _Elem* _StrTy; 
    typedef const _Elem* _ConstStrTy; 

    //... 

    public: 
     // Conversion operators so 'String' can easily be 
     // assigned to a C-String without calling 'c_str()'. 
    operator _StrTy() const { 
     return const_cast<_StrTy>(this->c_str()); 
    } 

    operator _ConstStrTy() const { 
     return this->c_str(); 
    } 

    // ... Constructors ... 

    /*------------ Additional Methods ------------*/ 

    //! Converts a value of the given type to a string. 
    template <class _ValTy> static String ConvertFrom(_ValTy val); 

    //! Converts a string to the given type. 
    template <class _ValTy> static _ValTy ConvertTo(const String& str); 
    template <class _ValTy> _ValTy ConvertTo(void) const; 

    //! Checks if a string is empty or is whitespace. 
    static bool IsNullOrSpace(const String& str); 
    bool IsNullOrSpace(void) const; 

    //! Converts a string to all upper-case. 
    static String ToUpper(String str); 
    void ToUpper(void); 

    // ... 
}; 

मैं कैसे template <class _ValTy> static String ConvertFrom(_ValTy val); को लागू कर सकता है? क्योंकि अब न केवल मुझे क्लास टेम्पलेट निर्दिष्ट करने की आवश्यकता है, बल्कि फ़ंक्शन टेम्पलेट भी। मैं दांव लगा रहा हूँ कोड के बारे में मैं लिखने के लिए कर रहा हूँ मान्य नहीं है, लेकिन यह दिखाना चाहिए कि मैं क्या पूरा करने के लिए कोशिश कर रहा हूँ:

MyString.cpp

template <class _Elem, class _Traits, class _Ax> 
template <class _ValTy> 
String<_Elem, _Traits, _Ax> String<_Elem, _Traits, _Ax>::ConvertFrom(_ValTy val) { 
    // Convert value to String and return it... 
} 

मैं टेम्पलेट्स के साथ उन्नत नहीं हूँ। न केवल मुझे बहुत संदेह है कि उपरोक्त मान्य है, यह लिखने के लिए बोझिल लगता है और बहुत पठनीय नहीं है। मैं टेम्पलेट विधियों को लागू करने के बारे में कैसे जाउंगा, और स्थैतिक टेम्पलेट विधियां जो अपना स्वयं का वर्ग प्रकार लौटाती हैं? क्योंकि मैं उन्हें शीर्षलेख में परिभाषित नहीं करना चाहता हूं।

+1

आपको शायद पढ़ना चाहिए: [टेम्पलेट केवल हेडर फ़ाइल में क्यों लागू किया जा सकता है?] (Http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the- शीर्ष लेख फ़ाइल)। –

+0

@ जेसे गुड यह मुझे दिखाता है कि एक स्रोत फ़ाइल में एक टेम्पलेट वर्ग से * सामान्य * विधि को अलग से लागू करने का एक तरीका है, लेकिन टेम्पलेट वर्ग से * templated * विधियों को कार्यान्वित करने का तरीका नहीं है। शायद मैं इस पोस्ट में कुछ देख रहा हूं, मैं उस लड़के बनना नहीं चाहता। क्या मुझे बस छोड़ देना चाहिए और आगे बढ़ना चाहिए और शीर्षलेख फ़ाइल में कक्षा विधियों को परिभाषित करना चाहिए? –

+0

यदि आप टेम्पलेट फ़ंक्शंस/कक्षाओं के लिए कार्यक्षमता से प्रोटोटाइप को अलग करने की कोशिश कर रहे हैं तो आप .inl प्रतिमान का उपयोग करने का प्रयास कर सकते हैं: जहां वास्तविक कार्यक्षमता .inl फ़ाइल है, और आप अपनी फ़ाइल फ़ाइल के अंत में उस फ़ाइल को शामिल करते हैं। – Alex

उत्तर

9

इससे पहले कि मैं आपके प्रश्न का उत्तर दूं, मुझे पहले कहना है: ऐसा मत करो। इसके बजाय फ्री-फ़ंक्शंस का उपयोग करके std::string बढ़ाएं, मानक लाइब्रेरी की तरह कई एल्गोरिदम लागू होते हैं। इसके अतिरिक्त मैं इसे string एस के बजाय श्रेणियों के लिए करने का सुझाव दूंगा लेकिन यह अधिक व्यक्तिपरक है।

यह भी ध्यान दें कि std::string आपके जीवन को कठिन बनाने के लिए सी-स्ट्रिंग्स पर निहित रूपांतरणों से बचाता है, लेकिन अप्रत्याशित अंतर्निहित रूपांतरणों के कारण होने वाली अस्पष्ट बगों की एक विस्तृत विविधता से आपके कोड को सुरक्षित रखने के लिए। मैं उन्हें लागू करने के बारे में बहुत लंबा और कठिन सोचता हूं। बस इसके बारे में सोचें: जब आप कोड लिखते हैं तो .c_str() टाइप करने के लिए आपको कुछ अतिरिक्त क्षण लगते हैं, और अनंतकाल के लिए जो भी आपके कोड को पढ़ता है, उसे तुरंत पता चलेगा कि इसे सी-स्टाइल स्ट्रिंग के रूप में उपयोग किया जा रहा है और नहीं std::string

आपके प्रश्न का उत्तर के लिए, बस शीर्षक में कोड डाल:

//! Converts a value of the given type to a string. 
template <class _ValTy> static String ConvertFrom(_ValTy val) 
{ 
    // Code here 
} 

अंत में ध्यान दें कि अंडरस्कोर + बड़े अक्षर (और कई अन्य चीजों _ से शुरू) के साथ शुरू पहचानकर्ता संकलक के लिए और इस तरह आरक्षित हैं सभी कार्यक्रम आपके प्रोग्राम की कार्यक्षमता के रूप में बंद हैं।

+1

+1 प्रश्न का उत्तर देने और मुझे कुछ समय बचाने वाली सलाह देने के लिए। धन्यवाद। –

2

आपकी फ़ंक्शन परिभाषा मान्य है, और इसे कम वर्बोज़ तरीके से कक्षा घोषणा के बाहर परिभाषित नहीं किया जा सकता है। चूंकि आप एक .cpp फ़ाइल में फ़ंक्शन परिभाषा डालना चाहते हैं, इसलिए आप अधिक संक्षिप्त फ़ंक्शन घोषणा के साथ फ़ंक्शन परिभाषा को संयोजित करने का लाभ नहीं उठा सकते हैं। एक .cpp फ़ाइल में फ़ंक्शन परिभाषा डालकर आपको स्पष्ट रूप से अपने टेम्पलेट वर्ग की सभी आवश्यक विशेषताओं को तुरंत चालू करना होगा।

13

टेम्पलेट के बाहर टेम्पलेट सदस्य कार्यों की परिभाषा की सिंटेक्स इस तरह है:

template <class T> struct A 
{ 
    template <class X> void f(); 
}; 

template<class T> template<class X> void A<T>::f() 
{ 
} 

तो आपका कोड सही है।

यह ध्यान रखना चाहते हैं कि .cpp में टेम्पलेट सदस्यों को परिभाषित करना बहुत उपयोगी नहीं है। इस मामले में आप उन्हें इस टेम्पलेट के साथ उपयोग करने के लिए आवश्यक सभी प्रकारों के साथ स्पष्ट रूप से तत्काल कर देंगे। या इन .cpp के बाहर उनका उपयोग न करें जो समझ में नहीं आता है।

+0

^धन्यवाद! आपने मेरा जीवन बचाया :) –

+0

@MathuSumMut जानना अच्छा है :-) – Rost