विभिन्न वस्तुओं का उपयोग करते समय टेम्पलेट विशेषज्ञता की कई परिभाषा


95

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

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

paulo@aeris:~/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

paulo@aeris:~/teste/cpp/redef$ cat other.h 
#include <iostream>

void other_func();

paulo@aeris:~/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);
}

paulo@aeris:~/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;
}

paulo@aeris:~/teste/cpp/redef$ cat Makefile
all:
    g++ -c other.c -o other.o -Wall -Wextra
    g++ main.c other.o -o main -Wall -Wextra

आखिरकार:

paulo@aeris:~/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 के अंदर "इनलाइन" को अनसुना कर देता हूं, तो कोड संकलित और चला जाएगा, लेकिन यह सिर्फ मुझे किसी तरह का "वर्कअराउंड" लगता है: क्या होगा यदि विशेष फ़ंक्शन बड़ा है और कई बार उपयोग किया जाता है? क्या मुझे एक बड़ा बाइनरी मिलेगा? ऐसा करने के लिए कोई और रास्ता नहीं है? यदि हाँ, तो कैसे? यदि नहीं, तो क्यों?

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

धन्यवाद


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

जवाबों:


129

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


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

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

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

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

इसलिए, यदि मेरी स्थैतिक सदस्य की परिभाषा पहले से है, template <typename T>तो यह हेडर में जा सकती है, और यदि यह है template<>तो यह नहीं हो सकता है?
वायलेट जिराफ

49

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

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


22

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

1) अपनी तात्कालिकता इनलाइन बनाओ।

2) एक हेडर में तात्कालिकता की घोषणा करें और फिर इसे एक सीपीपी में लागू करें।


वास्तव में एक 3 तरीका है जो उन लोगों को एक बिना नाम के नामस्थान में रखना है ... जो सी में स्थिर होने के समान है
एलेक्सिस विल्के

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

0

इस मुद्दे से संबंधित C ++ 11 मानक का कुछ अंश यहां दिया गया है :

फ़ंक्शन टेम्पलेट का एक स्पष्ट विशेषज्ञता केवल इनलाइन है, यदि इसे इनलाइन विनिर्देशक के साथ घोषित किया गया है या हटाए गए के रूप में परिभाषित किया गया है, और स्वतंत्र रूप से इसके फ़ंक्शन टेम्पलेट इनलाइन है। [ उदाहरण:

टेम्पलेट शून्य f (T) {/ * ... /} टेम्पलेट इनलाइन T g (T) {/ ... * /}

टेम्पलेट <> इनलाइन शून्य f <> (इंट) {/ * ... / // // ओके: इनलाइन टेम्प्लेट <> इंट जी <> (इंट) {/ ... * /} // ओके: इनलाइन नहीं - अंत उदाहरण ]

इसलिए यदि आप *.hफ़ाइल में टेम्प्लेट के कुछ स्पष्ट (उर्फ पूर्ण) विशेषज्ञ बनाते हैं , तो आपको ओडीआरinline के उल्लंघन से छुटकारा पाने में मदद करने की आवश्यकता होगी ।

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