2010-12-15 22 views
56

जब मैं विभिन्न ऑब्जेक्ट फ़ाइलों में एक विशेष टेम्पलेट का उपयोग करता हूं, तो मुझे लिंक करते समय "एकाधिक परिभाषा" त्रुटि मिलती है। मुझे मिला एकमात्र समाधान "इनलाइन" फ़ंक्शन का उपयोग करना शामिल है, लेकिन यह कुछ कामकाज की तरह लगता है। "इनलाइन" कीवर्ड का उपयोग किए बिना मैं इसे कैसे हल करूं? यदि यह संभव नहीं है, क्यों?टेम्पलेट विशेषज्ञता की एकाधिक परिभाषा

[email protected]ris:~/teste/cpp/redef$ cat hello.h 
#ifndef TEMPLATE_H 
#define TEMPLATE_H 

#include <iostream> 

template <class T> 
class Hello 
{ 
public: 
    void print_hello(T var); 
}; 

template <class T> 
void Hello<T>::print_hello(T var) 
{ 
    std::cout << "Hello generic function " << var << "\n"; 
} 

template <> //inline 
void Hello<int>::print_hello(int var) 
{ 
    std::cout << "Hello specialized function " << var << "\n"; 
} 

#endif 

[email protected]:~/teste/cpp/redef$ cat other.h 
#include <iostream> 

void other_func(); 

[email protected]:~/teste/cpp/redef$ cat other.c 
#include "other.h" 

#include "hello.h" 

void other_func() 
{ 
    Hello<char> hc; 
    Hello<int> hi; 

    hc.print_hello('a'); 
    hi.print_hello(1); 
} 

[email protected]:~/teste/cpp/redef$ cat main.c 
#include "hello.h" 

#include "other.h" 

int main() 
{ 
    Hello<char> hc; 
    Hello<int> hi; 

    hc.print_hello('a'); 
    hi.print_hello(1); 

    other_func(); 

    return 0; 
} 

:

यहाँ उदाहरण कोड है


अंत में

:

[email protected]:~/teste/cpp/redef$ make 
g++ -c other.c -o other.o -Wall -Wextra 
g++ main.c other.o -o main -Wall -Wextra 
other.o: In function `Hello<int>::print_hello(int)': 
other.c:(.text+0x0): multiple definition of `Hello<int>::print_hello(int)' 
/tmp/cc0dZS9l.o:main.c:(.text+0x0): first defined here 
collect2: ld returned 1 exit status 
make: ** [all] Erro 1 

अगर मैं hello.h अंदर "इनलाइन" uncomment, कोड संकलन होगा और चलाने के लिए, लेकिन यह है कि सिर्फ मेरे लिए "वैकल्पिक हल" किसी तरह का की तरह लगता है: क्या यदि विशेष कार्य बड़ा है और कई बार उपयोग किया जाता है? क्या मुझे एक बड़ी बाइनरी मिल जाएगी? ऐसा करने के लिए कोई और रास्ता नहीं है? यदि हां, तो कैसे? यदि नहीं, क्यों?

मैंने जवाब देखने की कोशिश की, लेकिन मुझे जो भी मिला वह बिना किसी स्पष्टीकरण के "इनलाइन का उपयोग" था।

धन्यवाद

+5

वास्तविक विशेष कार्यान्वयन को .cpp में डाल दिया गया है, फिर हेडर फ़ाइल – Anycorn

उत्तर

82

सहजता से, जब आप पूरी तरह से कुछ विशेषज्ञ करते हैं, तो यह किसी टेम्पलेट पैरामीटर पर निर्भर नहीं होता है - इसलिए जब तक आप विशेषज्ञता इनलाइन नहीं करते हैं, तो आपको इसे .hpp के बजाय एक .cpp फ़ाइल में रखना होगा। डेविड कहते हैं कि एक परिभाषा नियम का उल्लंघन समाप्त हो गया। ध्यान दें कि जब आप आंशिक रूप से टेम्पलेट्स का विशेषज्ञ हैं, आंशिक विशेषज्ञता अभी भी एक या अधिक टेम्पलेट पैरामीटर पर निर्भर करती है, इसलिए वे अभी भी .h फ़ाइल में जाते हैं।

+0

हमम मैं अभी भी थोड़ा उलझन में हूं कि यह ओडीआर को कैसे तोड़ता है। क्योंकि आप केवल एक बार पूरी तरह से विशिष्ट टेम्पलेट को परिभाषित करते हैं। आप विभिन्न ऑब्जेक्ट फ़ाइलों में ऑब्जेक्ट कई बार बना सकते हैं (यानी। इस मामले में इसे अन्य.c और main.c में तत्काल किया जाता है) लेकिन मूल ऑब्जेक्ट को केवल एक फ़ाइल में परिभाषित किया जाता है - इस मामले में 'hello.h' । –

+3

@ जस्टिन लिआंग: हेडर दो अलग-अलग .c फाइलों में शामिल है - इसका वही प्रभाव है जैसे कि आपने अपनी सामग्री (पूर्ण विशेषज्ञता सहित) सीधे उन फाइलों में लिखी होगी जिनमें प्रासंगिक स्थानों पर शामिल है। वन डेफिनिशन नियम (देखें http://en.wikipedia.org/wiki/One_Definition_Rule) कहता है (अन्य चीजों के साथ): "पूरे कार्यक्रम में, ऑब्जेक्ट या गैर-इनलाइन फ़ंक्शन में एक से अधिक परिभाषा नहीं हो सकती है"। इस मामले में, फ़ंक्शन टेम्पलेट का पूर्ण विशेषज्ञता सामान्य कार्य की तरह संक्षेप में है, इसलिए जब तक यह इनलाइन न हो, इसमें एक से अधिक परिभाषाएं नहीं हो सकती हैं। –

+0

हम्म, मैंने देखा कि जब हमारे पास एक टेम्पलेटेड विशेषज्ञता नहीं है तो यह त्रुटि दिखाई नहीं देगी। आइए मान लें कि हमारे पास दो अलग-अलग फ़ंक्शन थे जिन्हें हेडर फ़ाइल में कक्षा के बाहर परिभाषित किया गया था, वे अभी भी इनलाइन के बिना काम करेंगे? उदाहरण के लिए: http://pastebin.com/raw.php?i=bRaiNC7M। मैंने उस वर्ग को लिया और इसे दो फाइलों में शामिल किया। क्या इसका "प्रभाव जैसा नहीं होगा" जैसे कि आप सामग्री को सीधे दो फाइलों में लिखेंगे "और इस प्रकार एक एकाधिक परिभाषा त्रुटि होगी? –

30

कीवर्ड inline है संकलक कि प्रतीक वास्तविक इनलाइनिंग के बारे में की तुलना में एक परिभाषा नियम है, जो संकलक करते हैं या नहीं करने के लिए तय कर सकते हैं उल्लंघन करने के बिना एक से अधिक वस्तु फ़ाइल में मौजूद रहेंगे कह के बारे में अधिक करने के लिए।

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

15

आपने स्पष्ट रूप से अपने शीर्षलेख (void Hello<T>::print_hello(T var)) में एक टेम्पलेट को तुरंत चालू कर दिया है। यह कई परिभाषाएं बनाएगा। आप इसे दो तरीकों से हल कर सकते हैं:

1) अपनी तत्कालता इनलाइन बनाएं।

2) शीर्षलेख में तत्कालता घोषित करें और फिर इसे एक सीपीपी में कार्यान्वित करें।

+0

असल में एक तीसरा तरीका है जो उन्हें नाम नामस्थान में रखना है ... जो सी –

+2

में स्थिर होने के समान है। यह यहां मान्य नहीं है। मूल टेम्पलेट के रूप में एक ही नामस्थान में एक टेम्पलेट विशेषज्ञता होना आवश्यक है। –

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