2010-01-20 17 views
8

के अंदर और बाहर परिभाषित टेम्पलेट वर्ग के लिए सदस्य फ़ंक्शंस के बीच अंतर क्या वर्ग घोषणा के अंदर टेम्पलेट क्लास के लिए सदस्य फ़ंक्शंस को परिभाषित करने के बीच कोई अंतर है?वर्ग

अंदर निर्धारित:

template <typename T> 
class A 
{ 
public: 
    void method() 
    { 
     //... 
    } 
}; 

बाहर निर्धारित:

template <typename T> 
class B 
{ 
public: 
    void method(); 
}; 

template <typename T> 
void B<T>::method() 
{ 
    //... 
} 

गैर टेम्पलेट वर्गों के लिए, यह inlined और गैर inlined विधियों के बीच अंतर है। क्या यह टेम्पलेट कक्षाओं के लिए भी सच है?

मेरे अधिकांश सहयोगियों के लिए डिफ़ॉल्ट कक्षा के भीतर परिभाषाएं प्रदान करना है, लेकिन मैंने कक्षा के बाहर हमेशा परिभाषाओं को प्राथमिकता दी है। क्या मेरी वरीयता उचित है?

संपादित करें: कृपया मान लें कि उपर्युक्त कोड कक्षा के लिए शीर्षलेख फ़ाइल में प्रदान किया गया है।

+0

मैंने कभी भी संदर्भ नहीं देखा है जो इंगित करता है कि कक्षा घोषणा के अंदर एक विधि निकाय को परिभाषित करने से वह विधि इनलाइन हो जाती है। क्या मुझे कुछ याद आ रहा है? – Dathan

+0

@Dathan: यहां देखें: http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.8 और यहां: http: //msdn.microsoft.com/en-us /library/bw1hbe6y%28VS.80%29.aspx – Ben

+3

@Dathan: आप C++ मानक के §9.3/2 को याद कर रहे हैं, जो कहता है: "एक सदस्य फ़ंक्शन को इसकी कक्षा परिभाषा में परिभाषित किया जा सकता है (8.4) जिसमें यदि यह एक इनलाइन सदस्य फ़ंक्शन है ... "संपादित करें: यह भी ध्यान दें कि यह एक वर्ग परिभाषा है - एक वर्ग घोषणा कुछ ऐसा है:' वर्ग x; ' –

उत्तर

2

हां, टेम्पलेट कक्षाओं के लिए बिल्कुल सही है।

कारण टेम्पलेट कक्षाओं के लिए विधि परिभाषाओं को आम तौर पर इनलाइन होना पसंद किया जाता है यह है कि टेम्पलेट्स के साथ, टेम्पलेट को तत्काल होने पर पूरी परिभाषा दिखाई देनी चाहिए।

तो यदि आप कुछ अलग .cpp फ़ाइल में फ़ंक्शन परिभाषा डालते हैं, तो आपको एक लिंकर त्रुटि मिल जाएगी। एकमात्र सामान्य समाधान फ़ंक्शन इनलाइन को या तो कक्षा के अंदर या inline कीवर्ड के साथ परिभाषित करके करना है। लेकिन किसी भी मामले में, इसे कहीं भी फ़ंक्शन कहा जाता है, जिसका अर्थ है कि यह आमतौर पर वर्ग परिभाषा के समान ही शीर्षलेख में होना चाहिए।

+0

जिज्ञासा से बाहर, अब लिंकर त्रुटि सार्वभौमिक रूप से सच है? मुझे कुछ अतीत में पता है कंपाइलर्स ने विभिन्न टेम्पलेट इंस्टेंटेशन विकल्पों को प्रदान किया। उदाहरण के लिए, एसजीआई आईरिक्स सीसी कंपाइलर, लिंक-टाइम तत्कालता के लिए डिफॉल्ट किया गया और वास्तव में टेम्पलेट फ़ंक्शन परिभाषाओं को अपनी स्वयं की .cpp फ़ाइल में डालने को प्रोत्साहित करना प्रतीत होता था (यानी, हेडर में नहीं, गैर-रेखांकित, दृश्यमान नहीं किसी भी अन्य गैर-इनलाइन फ़ंक्शन परिभाषा की तरह कोड को कॉल करने के लिए)। बस सोच रहा है कि भाषा की आवश्यकता के लिए एक कंपाइलर वरीयता होने से इनलाइन टेम्पलेट फ़ंक्शन परिभाषा बदल गई है। – Darryl

+0

@ डेरिल, आप बाहरी टेम्पलेट का वर्णन कर रहे हैं। यह एक गैर है - मानक विस्तार, और सभी कंपाइलर्स इसका समर्थन नहीं करते हैं। नया मानक, सी ++ 1 एक्स, 'बाहरी' टेम्पलेट जोड़ रहा है, हालांकि मैं बेल यानी यह कीवर्ड की आवश्यकता है। – greyfade

+0

टेम्पलेट्स को प्रत्येक संकलन इकाई पर संकलित किया जाता है जो उस विशेष तत्कालता का उपयोग करता है, लेकिन वे 'कमजोर' प्रतीकों (जीसीसी शब्दावली, मुझे नहीं पता कि यह मानक कितना है) और एक से अधिक संकलन इकाई में परिभाषित एक ही प्रतीक होने पर एक लिंक त्रुटि नहीं है। तो टेम्पलेट कार्यों/विधियों में 'इनलाइन' जोड़ने की कोई आवश्यकता नहीं है। एक और टिप्पणी यह ​​है कि 'इनलाइन' कंपाइलर के लिए एक संकेत है, लेकिन इसे संकलक द्वारा उपेक्षा किया जा सकता है (लेकिन यह प्रभावित करेगा कि प्रतीक कैसे बनाए जाते हैं ताकि लिंकर डबल परिभाषा के बारे में शिकायत नहीं करेगा)। –

1

अधिक टाइप करने के अलावा, कोई अंतर नहीं है। इसमें template बिट, inline शामिल है और कक्षा का जिक्र करते समय अधिक "विस्तृत" नामों का उपयोग करना पड़ता है। उदाहरण

template <typename T> class A { 
    A method(A a) { 
    // whatever 
    } 
}; 

template <typename T> inline A<T> A<T>::method(A a) { 
    // whatever 
} 

नोट जब A<T> की चर्चा करते हुए कहा कि जब विधि के अंदर परिभाषित किया गया है आप हमेशा टेम्पलेट पैरामीटर सूची <T> छोड़ सकते हैं और सिर्फ A का उपयोग करें। इसे बाहर परिभाषित करते समय, आपको रिटर्न प्रकार में और विधि के नाम पर "पूर्ण" नाम का उपयोग करना होगा (लेकिन पैरामीटर सूची में नहीं)।

+0

आप दोनों मामलों में "विधि" इनलाइन बना रहे हैं, जो फ़ंक्शन बॉडी बड़ा होने पर खराब हो सकता है। यही वह है जिसे मैं टालने की कोशिश कर रहा हूं। – Ben

+2

** इनलाइन ** कीवर्ड वास्तव में कोड को अनुकूलित करने के साथ कम करना है, और इसके साथ ही एक ही फ़ंक्शन की एकाधिक परिभाषाओं की अनुमति है या नहीं।यदि किसी फ़ंक्शन को हेडर में परिभाषित किया गया है (जो टेम्पलेट्स के साथ अपरिहार्य है, या जब किसी वर्ग की घोषणा किसी वर्ग घोषणा के भीतर परिभाषित की जाती है), और एकाधिक संकलन इकाइयों में शामिल हैं, तो लिंकर अंततः कई (समान) परिभाषाओं के साथ समाप्त होगा एक ही समारोह/विधि। ** इनलाइन ** कीवर्ड (जो टेम्पलेट्स के साथ निहित होना चाहिए) लिंकर को बताता है कि यह ठीक है, अन्यथा यह एक लिंकर त्रुटि होगी। – UncleBens

+0

बिंदु बेन है कि एक टेम्पलेट के साथ आपके पास कोई विकल्प नहीं है। इसे इनलाइन चिह्नित किया जाना चाहिए या टेम्पलेट काम नहीं करेगा। यह एक कारण है कि कुछ लोग टेम्पलेट्स को नापसंद करते हैं। यह भी ध्यान देने योग्य है कि कंपाइलर को वास्तव में उस चीज़ को इनलाइन करना नहीं है जो वह आपकी पीठ के पीछे जो भी कर सकता है वह कर सकता है। – Goz

0

मुझे यह पता है..मुझे लगता है कि यह कुछ होना चाहिए जो आपको पूरा करने में मदद करता है?

// This might be in a header file: 
template <typename T> 
class xyz { 
    void foo(); 
    }; 

// ...

// This might be later on in the header file: 
    void xyz<T>::foo() { 
// generic definition of foo() 
    } 

यह एक के लिए गलत है:

defining a member function outside of its template 

यह इस तरह एक टेम्पलेट वर्ग के एक सदस्य समारोह की परिभाषा प्रदान करने के लिए ठीक नहीं है कुछ कारण तो यह है:

 void xyz<class T>::foo() { 
     // generic definition of foo() 
     } 

उचित परिभाषा टेम्पलेट कीवर्ड और एक ही टेम्पलेट तर्क वर्ग खाके की परिभाषा के साथ घोषित किया गया था की जरूरत है।ताकि देता है:

 template <typename T> 
      void xyz<T>::foo() { 
      // generic definition of foo() 
       } 

नोट इस तरह के सदस्य टेम्पलेट्स, आदि के रूप में टेम्पलेट निर्देशों के अन्य प्रकार, हैं कि, और प्रत्येक अपने स्वयं के प्रारूप पर ले जाता है। यह जानना महत्वपूर्ण है कि आपके पास कौन सा है, इसलिए आप जानते हैं कि प्रत्येक स्वाद को कैसे लिखना है। यह इसलिए विशेष रूप से है क्योंकि कुछ कंपाइलरों के त्रुटि संदेश गलत नहीं होने के कारण स्पष्ट नहीं हो सकते हैं। और निश्चित रूप से, एक अच्छी और अद्यतित किताब प्राप्त करें।

आप किसी टेम्पलेट के भीतर एक नेस्टेड सदस्य टेम्पलेट है, तो:

template <typename T> 
     struct xyz { 
     // ... 
     template <typename U> 
     struct abc; 
     // ... 
     }; 

कैसे आपने xyz के बाहर एबीसी परिभाषित करते हैं? यह काम नहीं करता:

 template <typename U> 
    struct xyz::abc<U> { // Nope 
     // ... 
    }; 

है और न ही ऐसा करता है:

template <typename T, typename U> 
struct xyz<T>::abc<U> { // Nope 
// ... 
}; 

आप ऐसा करने के लिए होगा:

 template <typename T> 
     template <typename U> 
      struct xyz<T>::abc { 
      // ... 
      }; 

ध्यान दें कि यह ...abc नहीं ...abc<U> है क्योंकि एबीसी एक "प्राथमिक" है टेम्पलेट। आईओएस, यह अच्छा नहीं है:

// यहां अनुमति नहीं है: टेम्पलेट टेम्पलेट संरचना xyz :: abc {};

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