2010-03-23 19 views
12

जब मैं एक टेम्पलेट वर्ग में एक (स्थिर) सदस्य फ़ंक्शन/स्थिरता का विशेषज्ञ हूं, तो मैं इस बात से उलझन में हूं कि घोषणा कहां है।टेम्पलेट क्लास सदस्य विशेषज्ञता की घोषणा

यहाँ मैं क्या क्या करना है, इसका एक उदाहरण - IBM's reference on template specialization से सीधे yoinked:

=== आईबीएम सदस्य विशेषज्ञता उदाहरण ===

template<class T> class X { 
public: 
    static T v; 
    static void f(T); 
}; 

template<class T> T X<T>::v = 0; 
template<class T> void X<T>::f(T arg) { v = arg; } 

template<> char* X<char*>::v = "Hello"; 
template<> void X<float>::f(float arg) { v = arg * 2; } 

int main() { 
    X<char*> a, b; 
    X<float> c; 
    c.f(10); // X<float>::v now set to 20 
} 

सवाल यह है कि, मैं कैसे इस में विभाजित है हेडर/सीपीपी फाइलें? सामान्य कार्यान्वयन स्पष्ट रूप से शीर्षलेख में है, लेकिन विशेषज्ञता के बारे में क्या है?

यह हेडर फ़ाइल में नहीं जा सकता है, क्योंकि यह ठोस है, जिससे कई परिभाषाएं होती हैं। लेकिन अगर यह .cpp फ़ाइल में जाता है, तो वह कोड है जो एक्स :: एफ() को विशेषज्ञता के बारे में जानता है, या यह सामान्य एक्स :: एफ() पर भरोसा कर सकता है?

अब तक मुझे केवल .cpp में विशेषज्ञता प्राप्त हुई है, जिसमें शीर्षलेख में कोई घोषणा नहीं है। मुझे संकलन या यहां तक ​​कि मेरे कोड को चलाने में समस्या नहीं है (जीसीसी पर, इस समय संस्करण को याद न करें), और यह अपेक्षित व्यवहार करता है - विशेषज्ञता को पहचानना। लेकिन ए) मुझे यकीन नहीं है कि यह सही है, और मैं जानना चाहता हूं कि क्या है, और बी) मेरे डॉक्सिजन दस्तावेज भयानक और बहुत भ्रामक हैं (उस पर में एक पल बाद में एक प्रश्न)।

क्या, कुछ इस तरह होगा मेरे लिए सबसे प्राकृतिक लगता है शीर्षक में विशेषज्ञता की घोषणा और सीपीपी में यह परिभाषित करने:

=== XClass.hpp ===

#ifndef XCLASS_HPP 
#define XCLASS_HPP 

template<class T> class X { 
public: 
    static T v; 
    static void f(T); 
}; 

template<class T> T X<T>::v = 0; 
template<class T> void X<T>::f(T arg) { v = arg; } 

/* declaration of specialized functions */ 
template<> char* X<char*>::v; 
template<> void X<float>::f(float arg); 

#endif 

=== XClass.cpp ===

#include <XClass.hpp> 

/* concrete implementation of specialized functions */ 
template<> char* X<char*>::v = "Hello"; 
template<> void X<float>::f(float arg) { v = arg * 2; } 

... लेकिन मैं अगर यह सही है पता नहीं है। कोई विचार?

उत्तर

9

आमतौर पर आप हेडर में विशेषज्ञता inline को परिभाषित करेंगे जैसे कि डर्कगेट ने कहा था।

// x.h: 
template<class T> struct X { 
    void f() {} 
} 

// declare specialization X<int>::f() to exist somewhere: 
template<> void X<int>::f(); 

// translation unit with definition for X<int>::f(): 
#include "x.h" 
template<> void X<int>::f() { 
    // ... 
} 

तो हाँ, अपने दृष्टिकोण ठीक लग रहा है:

आप हालांकि अगर आप संकलन बार या कोड ब्लोट को लेकर चिंतित हैं अलग अनुवाद इकाइयों में विशेषज्ञता परिभाषित कर सकते हैं। ध्यान दें कि आप केवल पूर्ण विशेषज्ञता के साथ ऐसा कर सकते हैं, इस प्रकार यह अक्सर ऐसा करने के लिए अव्यवहारिक होता है।

विवरण के लिए, उदा। देखें Comeaus template FAQ

+1

प्रश्न, जिज्ञासा से बाहर: क्यों इनलाइनिंग के लिए प्राथमिकता? यह लागू करने के लिए एक अजीब "आवश्यकता" प्रतीत होता है - कि "डिफ़ॉल्ट रूप से" एक टेम्पलेट विशेषज्ञता को रेखांकित किया जाएगा। मैं ये सब केवल इसलिए पूछता हूं क्योंकि आप यह कहते हैं कि आप "आमतौर पर" करते हैं, और मुझे नहीं लगता कि मैं आमतौर पर ऐसा क्यों करना चाहता हूं कि मैं आमतौर पर किसी भी अन्य फ़ंक्शन इनलाइन की घोषणा करना चाहता हूं। – Ziv

+0

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

+0

ठीक है, ज़ाहिर है, मैं केवल उन मामलों के बारे में बात कर रहा हूं जब एक पूर्ण विशेषज्ञता वांछित है, अन्यथा यह स्पष्ट रूप से एक पूरी कहानी है ... प्रश्न को फ्लिप करें, फिर: वे वही फायदे क्यों नहीं होंगे जो आम तौर पर हमें पसंद करते हैं सभी कार्यों को इनलाइन लिखें? – Ziv

4

उन्हें सभी को hpp फ़ाइल में रखें। कक्षा inline के बाहर परिभाषित विशेषज्ञता और कुछ भी बनाएं - जो कई परिभाषाओं का ख्याल रखेगा।

+0

दिलचस्प। लेकिन यह स्थैतिक चर के लिए काम नहीं करता है - केवल कार्यों के लिए। उस तरफ - क्या इससे निपटने के लिए एक और अधिक सुरुचिपूर्ण/मानक तरीका नहीं है? टेम्पलेट वर्ग सदस्य विशेषज्ञता टेम्पलेट प्रोग्रामिंग का एक प्रमुख हिस्सा है। निश्चित रूप से "आप घोषणा कहां डालते हैं" में "इनलाइन घोषित करें और संकलक को मूर्ख बनाएं" से अधिक सरल जवाब है? – Ziv

+0

@Ziv: मैंने सोचा था कि स्थिर चर हेडर में काम नहीं करेंगे, लेकिन मैंने इसे VS2008 में आजमाया है और ऐसा लगता है कि यह काम करता है। – quamrana

+1

विशेषज्ञता को किसी स्रोत फ़ाइल या हेडर में इनलाइन में परिभाषित किया जा सकता है, लेकिन इसे शीर्षलेख में घोषित किया जाना चाहिए। –

0

अपने प्रश्न का उत्तर करने के लिए: संकलक एक परिभाषा है जो अपनी आवश्यकताओं से मेल खाता देखता is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?

है, तो यह इसका इस्तेमाल होगा। अन्यथा यह सामान्य फ़ंक्शन कॉल उत्पन्न करेगा।

अपने पहले कोड स्निपेट में, आप X<T>::f(T arg) के लिए एक सामान्य परिभाषा की आपूर्ति, इसलिए संकलक float से अलग किसी भी T के लिए दृष्टांत होगा।

यदि आप जेनेरिक परिभाषा को छोड़ना चाहते हैं, तो संकलक X<double>::f(double) कहने के लिए कॉल उत्पन्न करेगा और लिंकर परिभाषा की खोज करेगा जो एक लिंकर त्रुटि के साथ समाप्त हो सकता है।

संक्षेप में: आपके पास हेडर में सबकुछ हो सकता है, क्योंकि टेम्पलेट्स के रूप में आपको कई परिभाषाएं नहीं मिलेंगी। यदि आपके पास केवल घोषणाएं हैं, तो आपको बाद में ढूंढने के लिए लिंकर के लिए कहीं और परिभाषाओं की आवश्यकता होगी।

+0

मेरा प्रश्न चारों ओर एक और तरीका है: यदि विशेष/घोषणा/विशेष घोषणा कैसे करें। एक टेम्पलेट विशेषज्ञता परिभाषा * शीर्षलेख में नहीं जा सकती है (जब तक कि रेखांकित नहीं किया गया है, जैसा कि स्पष्ट रूप से सुझाया गया है)। मैं कैसे सुनिश्चित करूं कि एक्स :: f() विशेषज्ञता को कॉल करता है, और गलती से जेनेरिक परिभाषा को कॉल नहीं करता है? – Ziv

+0

@Ziv: मेरी अपेक्षाओं के विपरीत, मेरे प्रयोग, कहते हैं कि सबकुछ * हेडर, स्थिर विशेषज्ञता और सभी में जा सकता है। – quamrana

+0

यह विषम है। मैंने कोशिश की, और मुझे एक "गुणा परिभाषित ..." त्रुटि मिली। हाँ संकलक अनुरूपता! – Ziv

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