एक .CPP फ़ाइल में C ++ टेम्पलेट फ़ंक्शन परिभाषाओं को संग्रहीत करना


526

मेरे पास कुछ टेम्प्लेट कोड हैं जिन्हें मैं हेडर में इनलाइन के बजाय सीपीपी फ़ाइल में संग्रहीत करना पसंद करूंगा। मुझे पता है कि यह तब तक किया जा सकता है जब तक आप जानते हैं कि किस प्रकार के टेम्पलेट का उपयोग किया जाएगा। उदाहरण के लिए:

.h फ़ाइल

class foo
{
public:
    template <typename T>
    void do(const T& t);
};

.cpp फ़ाइल

template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);

अंतिम दो पंक्तियों पर ध्यान दें - foo :: do टेम्पलेट फ़ंक्शन केवल ints और std :: strings के साथ उपयोग किया जाता है, इसलिए उन परिभाषाओं का अर्थ है कि ऐप लिंक करेगा।

मेरा सवाल है - यह एक बुरा हैक है या यह अन्य संकलक / लिंकर्स के साथ काम करेगा? मैं इस समय केवल VS2008 के साथ इस कोड का उपयोग कर रहा हूं, लेकिन अन्य वातावरणों में पोर्ट करना चाहता हूं।


22
मुझे पता नहीं था कि यह संभव था - एक दिलचस्प चाल! यह जानने के लिए कुछ हालिया कार्यों में मदद मिली होगी - चीयर्स!
xan

69
जो चीज मुझे परेशान करती है वह doएक पहचानकर्ता के रूप में उपयोग है : पी
क्वेंटिन

मैंने gcc के साथ सोमरिंग भी किया है, लेकिन फिर भी शोध कर रहा हूं
निक

16
यह "हैक" नहीं है, यह आगे की घोषणा है। भाषा के मानक में इसका स्थान है; हां, यह हर मानक अनुरूप संकलक में अनुमत है।
अहमत इपकीन

1
यदि आपके पास दर्जनों विधियां हैं तो क्या होगा? क्या आप केवल template class foo<int>;template class foo<std::string>;.cpp फ़ाइल के अंत में कर सकते हैं ?
अज्ञानी

जवाबों:


231

आपके द्वारा वर्णित समस्या को हेडर में टेम्पलेट को परिभाषित करके या आपके द्वारा वर्णित दृष्टिकोण के माध्यम से हल किया जा सकता है।

मैं C ++ FAQ Lite से निम्नलिखित बिंदुओं को पढ़ने की सलाह देता हूं :

वे इन (और अन्य) टेम्पलेट मुद्दों के बारे में बहुत विस्तार से जाते हैं।


39
बस उत्तर को पूरक करने के लिए, संदर्भित लिंक सकारात्मक रूप से प्रश्न का उत्तर देता है, अर्थात यह संभव है कि रोब ने क्या सुझाव दिया है और पोर्टेबल होने का कोड है।
ivotron

160
क्या आप उत्तर में ही संबंधित भागों को पोस्ट कर सकते हैं? एसओ पर भी इस तरह के जिक्र की इजाजत क्यों है। मुझे इस कड़ी में क्या देखना है, इसका कोई सुराग नहीं है क्योंकि यह भारी रूप से बदल दिया गया है।
पहचान करें

124

इस पृष्ठ के अन्य लोगों के लिए यह स्पष्ट है कि स्पष्ट टेम्पलेट विशेषज्ञता (या कम से कम VS2008 में) के लिए सही सिंटैक्स क्या है (इसके बारे में), इसके निम्नलिखित ...

आपकी .h फ़ाइल में ...

template<typename T>
class foo
{
public:
    void bar(const T &t);
};

और अपने .cpp फ़ाइल में

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;

15
क्या आपका मतलब है "स्पष्ट कक्षा टेम्पलेट विशेष के लिए"। उस मामले में जो टेम्पर्ड क्लास के हर फंक्शन को कवर करेगा?
आर्थर

@ आर्थर ऐसा नहीं लगता है, मेरे पास कुछ टेम्पलेट तरीके हैंडर में रहते हैं और अधिकांश अन्य तरीके सीपीपी में, ठीक काम करते हैं। बहुत अच्छा समाधान है।
15:16 बजे user1633272

पूछने वाले के मामले में, उनके पास एक फ़ंक्शन टेम्पलेट है, न कि क्लास टेम्पलेट।
user253751

23

यह कोड अच्छी तरह से बनाया गया है। आपको केवल यह ध्यान देना है कि तात्कालिकता के बिंदु पर टेम्पलेट की परिभाषा दिखाई दे रही है। मानक उद्धृत करने के लिए, § 14.7.2.4:

एक गैर-निर्यात किए गए फ़ंक्शन टेम्पलेट की परिभाषा, एक गैर-निर्यात सदस्य फ़ंक्शन टेम्पलेट या एक गैर-निर्यात किए गए सदस्य फ़ंक्शन या क्लास टेम्पलेट के स्थिर डेटा सदस्य प्रत्येक अनुवाद इकाई में मौजूद होंगे जिसमें यह स्पष्ट रूप से त्वरित रूप से लिखा गया है।


2
गैर-निर्यात का क्या मतलब है?
दान निसानबाम

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

धन्यवाद। मैंने सोचा था कि सभी फ़ंक्शन संकलन इकाई के बाहर दिखाई देते हैं (डिफ़ॉल्ट रूप से)। यदि मेरे पास दो संकलन इकाइयाँ हैं a.cpp(फ़ंक्शन को परिभाषित करना a() {}) और b.cpp(फ़ंक्शन को परिभाषित करना b() { a() }), तो यह सफलतापूर्वक लिंक करेगा। अगर मैं सही हूं, तो उपरोक्त उद्धरण ठेठ मामले के लिए आवेदन नहीं करने के लिए प्रतीत होता है ... क्या मैं कहीं गलत हो रहा हूं?
दान निसानबाम

@ दान तुच्छ प्रतिघात: inlineकार्य
कोनराड रूडोल्फ

1
@Dan फंक्शन टेम्प्लेट स्पष्ट रूप से होते हैं inline। इसका कारण यह है कि एक मानकीकृत C ++ ABI के बिना इस प्रभाव को परिभाषित करना कठिन / असंभव है जो कि अन्यथा होगा।
कोनराड रुडोल्फ

15

यह ठीक काम करना चाहिए हर जगह टेम्पलेट्स समर्थित हैं। स्पष्ट टेम्पलेट तात्कालिकता C ++ मानक का हिस्सा है।


13

आपका उदाहरण सही है लेकिन बहुत पोर्टेबल नहीं है। थोड़ा क्लीनर सिंटैक्स भी है जिसका उपयोग किया जा सकता है (जैसा कि @ नामस्थान-साइड द्वारा बताया गया है)।

मान लीजिए कि टेम्प्लेटेड क्लास कुछ लाइब्रेरी का हिस्सा है जिसे साझा किया जाना है। क्या टेम्प्लेटेड क्लास के अन्य संस्करणों को संकलित किया जाना चाहिए? क्या पुस्तकालय अनुचर वर्ग के सभी संभावित टेम्पलेटेड उपयोगों का अनुमान लगाने वाला है?

एक वैकल्पिक दृष्टिकोण आपके पास जो कुछ भी है उस पर थोड़ा बदलाव है: एक तीसरी फ़ाइल जोड़ें जो टेम्पलेट कार्यान्वयन / इंस्टेंटेशन फ़ाइल है।

foo.h फ़ाइल

// Standard header file guards omitted

template <typename T>
class foo
{
public:
    void bar(const T& t);
};

foo.cpp फ़ाइल

// Always include your headers
#include "foo.h"

template <typename T>
void foo::bar(const T& t)
{
    // Do something with t
}

foo-impl.cpp फ़ाइल

// Yes, we include the .cpp file
#include "foo.cpp"
template class foo<int>;

एक चेतावनी यह है कि आपको संकलक को यह बताने की ज़रूरत है कि बाद में संकलन करने के foo-impl.cppबजाय foo.cppकुछ नहीं करना है।

बेशक, आपके पास तीसरी फ़ाइल में कई कार्यान्वयन हो सकते हैं या आपके द्वारा उपयोग किए जाने वाले प्रत्येक प्रकार के लिए कई कार्यान्वयन फ़ाइलें हो सकती हैं।

यह अन्य उपयोगों के लिए टेम्प्लेटेड क्लास को साझा करते समय अधिक लचीलेपन को सक्षम करता है।

यह सेटअप पुन: उपयोग की गई कक्षाओं के लिए संकलन समय को भी कम कर देता है क्योंकि आप प्रत्येक अनुवाद इकाई में एक ही हेडर फ़ाइल को फिर से जमा नहीं कर रहे हैं।


यह आपको क्या खरीदता है नई विशेषज्ञता जोड़ने के लिए आपको अभी भी foo-impl.cpp को संपादित करना होगा।
एम.के.

कार्यान्वयन विवरणों की अलगकरण (उर्फ परिभाषाएँ foo.cpp) जिसमें से संस्करण वास्तव में संकलित (इन foo-impl.cpp) और घोषणाएँ (इन foo.h) हैं। मुझे नापसंद है कि ज्यादातर C ++ टेम्प्लेट पूरी तरह से हेडर फाइलों में परिभाषित हैं। यह c[pp]/hप्रत्येक वर्ग / नाम स्थान / जो भी आप उपयोग करते हैं उसके लिए जोड़े के C / C ++ मानक के लिए काउंटर है । लोगों को अभी भी अखंड हेडर फ़ाइलों का उपयोग केवल इसलिए लगता है क्योंकि यह विकल्प व्यापक रूप से उपयोग या ज्ञात नहीं है।
कैमरन टैकलिंड

1
@MK। मैं पहली बार स्रोत फ़ाइल में परिभाषा के अंत में स्पष्ट टेम्पलेट तात्कालिकता डाल रहा था जब तक कि मुझे कहीं और तात्कालिकता की आवश्यकता नहीं थी (उदाहरण के लिए टेम्पर्ड प्रकार के रूप में एक नकली का उपयोग करके यूनिट परीक्षण)। यह अलगाव मुझे बाहरी रूप से अधिक तात्कालिकता जोड़ने की अनुमति देता है। इसके अलावा, यह तब भी काम करता है जब मैं मूल को एक h/cppजोड़ी के रूप में रखता हूं, हालांकि मुझे शामिल गार्ड में तात्कालिकता की मूल सूची को घेरना था, लेकिन मैं अभी भी foo.cppसामान्य रूप से संकलित कर सकता था । मैं अभी भी C ++ के लिए काफी नया हूं, लेकिन यह जानना चाहूंगा कि क्या इस मिश्रित उपयोग का कोई अतिरिक्त कैवेट है या नहीं।
तीसरा पानी

3
मुझे लगता है कि यह सड़न रोकने के लिए बेहतर है foo.cppऔर foo-impl.cpp। फ़ाइल #include "foo.cpp"में नहीं foo-impl.cpp; इसके बजाय, घोषणा जोड़ने extern template class foo<int>;के लिए foo.cppजब संकलन टेम्पलेट instantiating से संकलक को रोकने के लिए foo.cpp। सुनिश्चित करें कि बिल्ड सिस्टम दोनों .cppफ़ाइलों का निर्माण करता है और दोनों ऑब्जेक्ट फ़ाइलों को लिंकर में पास करता है। इसके कई लाभ हैं: क) यह स्पष्ट है foo.cppकि इसमें कोई तात्कालिकता नहीं है; b) foo.cpp में परिवर्तन को foo-impl.cpp के पुनर्संयोजन की आवश्यकता नहीं है।
शमूएल लेविन

3
यह उन टेम्पलेट परिभाषाओं की समस्या के लिए एक बहुत अच्छा दृष्टिकोण है जो दोनों दुनिया में सबसे अच्छा लगता है - हेडर कार्यान्वयन और अक्सर उपयोग किए जाने वाले प्रकारों के लिए तात्कालिकता। इस सेटअप में जो एकमात्र बदलाव होगा, उसका नाम बदलकर सिर्फ और सिर्फ नाम foo.cppकरना है । मैं भी typedefs instantiations के लिए से जोड़ना होगा करने के लिए , वैसे ही । चाल उपयोगकर्ताओं को एक पसंद के लिए दो हेडर इंटरफेस प्रदान करने के लिए है। जब उपयोगकर्ता को पूर्व-परिभाषित तात्कालिकता की आवश्यकता होती है, जिसमें वह शामिल होता है , जब उपयोगकर्ता को आदेश में से कुछ की आवश्यकता होती है । foo_impl.hfoo-impl.cppfoo.cppfoo.cppfoo.husing foo_int = foo<int>;foo.hfoo_impl.h
वर्म

5

यह निश्चित रूप से एक बुरा हैक नहीं है, लेकिन इस तथ्य से अवगत रहें कि आपको हर वर्ग / प्रकार के लिए इसे (स्पष्ट टेम्पलेट विशेषज्ञता) करना होगा जिसे आप दिए गए टेम्पलेट के साथ उपयोग करना चाहते हैं। टेम्पलेट की तात्कालिकता का अनुरोध करने वाले MANY प्रकार के मामले में आपकी .cpp फ़ाइल में बहुत सारी लाइनें हो सकती हैं। इस समस्या को हल करने के लिए आप अपने द्वारा उपयोग की जाने वाली प्रत्येक परियोजना में एक TemplateClassInst.cpp रख सकते हैं ताकि आपके पास अधिक से अधिक नियंत्रण हो कि किस प्रकार का त्वरित मूल्यांकन किया जाएगा। जाहिर है यह समाधान एकदम सही नहीं होगा (उर्फ चांदी की गोली) जैसा कि आप अंत में ओडीआर :) को तोड़ सकते हैं।


क्या आप निश्चित हैं कि यह ODR को तोड़ देगा? यदि TemplateClassInst.cpp में इंस्टेंटेशन लाइनें समान स्रोत फ़ाइल (टेम्प्लेट फ़ंक्शन फ़ंक्शन परिभाषाओं से युक्त) को संदर्भित करती हैं, तो क्या यह गारंटी नहीं है कि सभी परिभाषाएँ समान होने के बावजूद ODR का उल्लंघन नहीं किया जाता है (भले ही दोहराया जाए)?
दान निसानबाम

कृपया, ODR क्या है?
नॉनमोएबल

4

नवीनतम मानक में, एक कीवर्ड ( export) है जो इस समस्या को कम करने में मदद करेगा, लेकिन इसे किसी भी संकलक में लागू नहीं किया जाता है, जिसे मैं कोमू के अलावा अन्य के बारे में जानता हूं।

इस बारे में अक्सर पूछे जाने वाले प्रश्न देखें ।


2
AFAIK, निर्यात मृत है क्योंकि वे नए और नए मुद्दों का सामना कर रहे हैं, हर बार वे अंतिम हल करते हैं, जिससे समग्र समाधान अधिक से अधिक जटिल हो जाता है। और "निर्यात" कीवर्ड आपको सीपीपी (वैसे भी एच। सटर के वैसे भी) से "निर्यात" करने में सक्षम नहीं करेगा। तो मैं कहता हूं: अपनी सांस को रोककर मत
रखो

2
निर्यात को लागू करने के लिए कंपाइलर को अभी भी पूर्ण टेम्पलेट परिभाषा की आवश्यकता है। आपको जो कुछ भी मिल रहा है, वह एक तरह के संकलित रूप में है। लेकिन वास्तव में इसका कोई मतलब नहीं है।
ज़ान लिंक्स

2
... और यह मानक से चला गया है, न्यूनतम लाभ के लिए अत्यधिक जटिलता के कारण।
DevSolar

4

यह टेम्पलेट फ़ंक्शन को परिभाषित करने का एक मानक तरीका है। मुझे लगता है कि टेम्पलेट को परिभाषित करने के लिए मैंने तीन विधियाँ पढ़ी हैं। या शायद 4. पेशेवरों और विपक्षों के साथ प्रत्येक।

  1. वर्ग परिभाषा में परिभाषित करें। मुझे यह बिल्कुल पसंद नहीं है क्योंकि मुझे लगता है कि कक्षा की परिभाषाएं संदर्भ के लिए कड़ाई से हैं और पढ़ने में आसान होनी चाहिए। हालाँकि यह बाहर की तुलना में कक्षा में टेम्पलेट्स को परिभाषित करने के लिए बहुत कम मुश्किल है। और सभी टेम्पलेट घोषणाएँ जटिलता के समान स्तर पर नहीं हैं। यह विधि टेम्पलेट को एक सच्चे टेम्पलेट भी बनाती है।

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

  3. शीर्ष लेख को शामिल करें ।h और कार्यान्वयन .CPP को अपने main.CPP में शामिल करें। मुझे लगता है कि यह कैसे किया जाता है। आपको किसी भी पूर्व तात्कालिकता को तैयार नहीं करना होगा, यह एक सच्चे टेम्पलेट की तरह व्यवहार करेगा। मेरे पास जो समस्या है, वह यह है कि यह स्वाभाविक नहीं है। हम आम तौर पर शामिल नहीं करते हैं और स्रोत फ़ाइलों को शामिल करने की उम्मीद करते हैं। मुझे लगता है कि जब से आप स्रोत फ़ाइल को शामिल करते हैं, तो टेम्पलेट फ़ंक्शन इनबिल्ट हो सकते हैं।

  4. यह अंतिम विधि, जो पोस्ट किया गया तरीका था, एक स्रोत फ़ाइल में टेम्प्लेट को नंबर 3 की तरह परिभाषित कर रहा है; लेकिन स्रोत फ़ाइल को शामिल करने के बजाय, हम उन टेम्पलेट को त्वरित रूप से भेजते हैं जिनकी हमें आवश्यकता होगी। मुझे इस पद्धति से कोई समस्या नहीं है और यह कभी-कभी काम आती है। हमारे पास एक बड़ा कोड है, यह इनबिल्ट होने से लाभ नहीं उठा सकता है इसलिए इसे केवल CPP फ़ाइल में रखें। और अगर हम सामान्य तात्कालिकता को जानते हैं और हम उन्हें पूर्वनिर्धारित कर सकते हैं। यह हमें मूल रूप से एक ही चीज को 5, 10 बार लिखने से बचाता है। इस पद्धति का लाभ हमारे कोड के स्वामित्व को बनाए रखने में है। लेकिन मैं CPP फ़ाइलों में छोटे, नियमित रूप से उपयोग किए जाने वाले कार्यों को लगाने की सलाह नहीं देता। जैसा कि यह आपके पुस्तकालय के प्रदर्शन को कम करेगा।

ध्यान दें, मैं एक फूला हुआ obj फ़ाइल के परिणामों के बारे में पता नहीं है।


3

हां, यह स्पेशलाइजेशन क्लियर इंस्टेंटेशन करने का मानक तरीका है। जैसा कि आपने कहा था, आप इस टेम्पलेट को अन्य प्रकारों से नहीं देख सकते।

संपादित करें: टिप्पणी के आधार पर सही किया गया।


शब्दावली के बारे में picky होने के नाते यह एक "स्पष्ट तात्कालिकता" है।
रिचर्ड कॉर्डन

2

आइए एक उदाहरण लेते हैं, आइए बताते हैं कि आप किस कारण से एक खाका बनाना चाहते हैं:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

यदि आप विजुअल स्टूडियो के साथ इस कोड को संकलित करते हैं - यह आउट ऑफ बॉक्स काम करता है। gcc लिंकर त्रुटि उत्पन्न करेगा (यदि एक ही हेडर फ़ाइल का उपयोग कई .cpp फ़ाइलों से किया जाता है):

error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here

कार्यान्वयन को .cpp फ़ाइल में ले जाना संभव है, लेकिन फिर आपको इस तरह वर्ग घोषित करने की आवश्यकता है -

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

template <>
void DemoT<int>::test();

template <>
void DemoT<bool>::test();

// Instantiate parametrized template classes, implementation resides on .cpp side.
template class DemoT<bool>;
template class DemoT<int>;

और फिर .cpp इस तरह दिखेगा:

//test_template.cpp:
#include "test_template.h"

template <>
void DemoT<int>::test()
{
    printf("int test (int)\n");
}


template <>
void DemoT<bool>::test()
{
    printf("int test (bool)\n");
}

हेडर फ़ाइल में दो अंतिम पंक्तियों के बिना - gcc ठीक काम करेगा, लेकिन विज़ुअल स्टूडियो एक त्रुटि उत्पन्न करेगा:

 error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test@?$DemoT@H@@QEAAXXZ) referenced in function

टेम्पलेट वर्ग वाक्यविन्यास मामले में वैकल्पिक है अगर आप .dll निर्यात के माध्यम से समारोह का पर्दाफाश करना चाहते हैं, लेकिन यह केवल विंडोज़ प्लेटफॉर्म के लिए लागू होता है - तो test_template.h ऐसा दिखाई दे सकता:

//test_template.h:
#pragma once
#include <cstdio>

template <class T>
class DemoT
{
public:
    void test()
    {
        printf("ok\n");
    }
};

#ifdef _WIN32
    #define DLL_EXPORT __declspec(dllexport) 
#else
    #define DLL_EXPORT
#endif

template <>
void DLL_EXPORT DemoT<int>::test();

template <>
void DLL_EXPORT DemoT<bool>::test();

पिछले उदाहरण से .cpp फ़ाइल के साथ।

हालांकि यह लिंकर को अधिक सिरदर्द देता है, इसलिए यदि आप .dll फ़ंक्शन को निर्यात नहीं करते हैं तो पिछले उदाहरण का उपयोग करने की अनुशंसा की जाती है।


1

एक अद्यतन के लिए समय! एक इनलाइन (.inl, या शायद कोई अन्य) फ़ाइल बनाएँ और बस इसमें अपनी सभी परिभाषाएँ कॉपी करें। प्रत्येक फ़ंक्शन के ऊपर टेम्पलेट जोड़ना सुनिश्चित करें ( template <typename T, ...>)। अब इनलाइन फ़ाइल में हेडर फ़ाइल को शामिल करने के बजाय आप इसके विपरीत करें। अपनी कक्षा की घोषणा के बाद इनलाइन फ़ाइल शामिल करें ( #include "file.inl")।

मैं वास्तव में नहीं जानता कि किसी ने इसका उल्लेख क्यों नहीं किया है। मुझे तत्काल कमियां नहीं दिखतीं।


25
तात्कालिक कमियां यह मौलिक रूप से उसी तरह है जैसे कि हेडर में सीधे टेम्पलेट फ़ंक्शन को परिभाषित करना। एक बार जब आप #include "file.inl", प्रीप्रोसेसर file.inlसीधे हेडर की सामग्री को पेस्ट करने जा रहा है । हेडर में जाने वाले कार्यान्वयन से बचने के लिए आप जो भी कारण चाहते हैं, यह समाधान उस समस्या को हल नहीं करता है।
कोड़ी ग्रे

5
- और इसका मतलब है कि आप तकनीकी रूप से अनावश्यक रूप से, अपने आप को बोझिल कर रहे हैं / सभी क्रियाओं को लिखने का कार्य, आउट-ऑफ-द-लाइन templateपरिभाषाओं द्वारा आवश्यक माइंड-झुकने बॉयलरप्लेट । मुझे लगता है कि लोग ऐसा क्यों करना चाहते हैं - गैर-टेम्प्लेट घोषणाओं / परिभाषाओं के साथ सबसे अधिक समता प्राप्त करने के लिए, इंटरफ़ेस घोषणा को चुस्त दिखते रहने के लिए, आदि - लेकिन यह हमेशा परेशानी के लायक नहीं है। यह दोनों तरफ के व्यापार-नापसंद का मूल्यांकन करने और कम से कम बुरा चुनने का मामला है । ... जब तक namespace classएक चीज़ नहीं बन जाती: ओ [ कृपया एक चीज़ बनो ]
अंडरस्कोर_ड

2
@ और यह लगता है कि समिति के पाइप में फंस गए हैं, हालांकि मुझे लगता है कि मैंने किसी को यह कहते हुए देखा कि यह जानबूझकर नहीं था। काश, इसे C ++ 17 में बनाया जाता। शायद अगले दशक।
अंडरस्कोर_ड

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

0

आपके द्वारा दिए गए उदाहरण में कुछ भी गलत नहीं है। लेकिन मुझे कहना होगा कि मुझे विश्वास है कि यह एक सीपी फ़ाइल में फ़ंक्शन परिभाषाओं को संग्रहीत करने के लिए कुशल नहीं है। मैं केवल फ़ंक्शन की घोषणा और परिभाषा को अलग करने की आवश्यकता को समझता हूं।

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


8
इसके बारे में क्या अक्षम है?
कोड़ी ग्रे

0

उपरोक्त में से कोई भी मेरे लिए काम नहीं करता है, इसलिए यहां बताया गया है कि y ने इसे कैसे हल किया, मेरी कक्षा में केवल 1 विधि है।

class Model
{
    template <class T>
    void build(T* b, uint32_t number);
};

सीपीपी

#include "Model.h"
template <class T>
void Model::build(T* b, uint32_t number)
{
    //implementation
}

void TemporaryFunction()
{
    Model m;
    m.build<B1>(new B1(),1);
    m.build<B2>(new B2(), 1);
    m.build<B3>(new B3(), 1);
}

यह लिंकर त्रुटियों से बचता है, और TemporaryFunction को कॉल करने की कोई आवश्यकता नहीं है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.