2013-04-22 29 views
6

क्यों मैं एक दोस्त फ़ंक्शन के लिए एक ही टेम्पलेट पैरामीटर का उपयोग नहीं कर सकता जो टेम्पलेट तर्क लेता है? मेरा मतलब है कि नीचे दिया गया कोड ठीक है!ऑपरेटर << (ostream & os, ...) टेम्पलेट वर्ग

template <class Vertex> 
class Edge 
{ 
    template <class T> 
    friend ostream& operator<<(ostream& os, const Edge<T>& e); 
    /// ... 
}; 


template <class T> 
ostream& operator<<(ostream& os, const Edge<T>& e) 
{ 
    return os << e.getVertex1() << " -> " << e.getVertex2(); 
} 

लेकिन यह ठीक नहीं है। क्यूं कर? समस्या क्या है? (मैं लिंकर त्रुटि मिलती है।)

template <class Vertex> 
class Edge 
{ 
    friend ostream& operator<<(ostream& os, const Edge<Vertex>& e); 
    /// ... 
}; 

template <class T> 
ostream& operator<<(ostream& os, const Edge<T>& e) 
{ 
    return os << e.getVertex1() << " -> " << e.getVertex2(); 
} 
+1

एक दोस्त एक टेम्पलेट है, अन्य है नहीं। – Xeo

उत्तर

3

आप निम्न

template <class Vertex> 
class Edge 
{ 
    friend ostream& operator<< <>(ostream& os, const Edge<Vertex>& e); 
    /// ... 
}; 

Edge करने के लिए operator << <Vertex> दोस्त बनाता है कि उपयोग कर सकते हैं।

अपने दूसरे मामले में - आप दोस्त गैर टेम्पलेट ऑपरेटर करते हैं, लेकिन ताकि आप संदर्भ अपरिभाषित है, लेकिन इस मामले अगर आप चाहते हैं इस्तेमाल किया जा सकता इस ऑपरेटर की परिभाषा, टेम्पलेट है आपके लिए ठोस Edge (Edge<int> उदाहरण के लिए) operator <<

+1

इसे 'ऑपरेटर <<' फ़ंक्शन टेम्पलेट की अग्रेषित घोषणा की आवश्यकता होगी (जिसके बदले में 'एज' वर्ग टेम्पलेट की अगली घोषणा की आवश्यकता होगी)। –

2
template <class T> 
friend ostream& operator<<(ostream& os, const Edge<T>& e); 

कहते हैं, वहाँ है टेम्प्लेटेडoperator << बाहर, इसके साथ दोस्त हो, और सब कुछ ठीक है।

 

friend ostream& operator<<(ostream& os, const Edge<Vertex>& e); 

कहते हैं, वहाँ है एक operator << बाहर, इसके साथ दोस्त हो ... और संकलक ऐसी बात नहीं मिल रहा।

ऑपरेटर को टेम्पलेट करने वाले कंपाइलर को बताने के लिए, <> द्वारा उसे फॉरएवरआर के रूप में वर्णित करने में सहायता करें (उसने मुझे तेजी से हराया :- डी)।

2
समस्या

है कि यहाँ:

friend ostream& operator<<(ostream& os, const Edge<Vertex>& e); 

आप एक गैर टेम्पलेट समारोह (जो Edge से प्रत्येक इन्स्टेन्शियशन के लिए अलग होगा) की घोषणा कर रहे हैं एक friend, और नहीं टेम्पलेट के इन्स्टेन्शियशन होने के लिए ।

मैंने देखा है कि सबसे आम समाधान बस वर्ग टेम्पलेट परिभाषा में operator<< इनलाइन को लागू करना है। वैकल्पिक रूप से, आप एक सार्वजनिक सदस्य फ़ंक्शन प्रदान कर सकते हैं जो आउटपुट करता है, और इसे operator<< फ़ंक्शन टेम्पलेट से आमंत्रित करता है। या फिर आप लिख सकते हैं:

friend ostream& operator<< <Vertex>(ostream&, Edge<Vertex> const&); 

संकलक कि operator<< एक दोस्त है जो है एक टेम्पलेट का एक इन्स्टेन्शियशन बताने के लिए। आईआईयूसी, हालांकि, यह केवल काम करता है यदि लक्ष्यित operator<< फ़ंक्शन इस बिंदु पर दिखाई देने वाले टेम्पलेट की घोषणा है, जिसका अर्थ है कि आपको को आगे घोषित करने की आवश्यकता है (और इसे घोषित करने के लिए, कक्षा को आगे घोषित करें टेम्पलेट)।

समस्या की इस तरह के लिए मेरा सामान्य समाधान प्रदान करने के लिए एक सामान्य सदस्य समारोह print है, और फिर से निकाले जाते हैं:

template <typename DerivedType> 
class IOStreamOperators 
{ 
public: 
    friend std::ostream&operator<<(
     std::ostream&  dest, 
     DerivedType const& source) 
    { 
     source.print(dest) ; 
     return dest ; 
    } 

    friend std::istream&operator>>(
     std::istream&  source, 
     DerivedType&  dest) 
    { 
     dest.scan(source) ; 
     return source ; 
    } 

protected: 
    ~IOStreamOperators() {} 
}; 

, जैसे:

template <class Vertex> 
class Edge : public IOStreamOperators<Edge<Vertex> > 
{ 
    // ... 
    void print(std::ostream& dest) 
    { 
     // ... 
    } 
}; 

मैं इस पाया है कि अंत में कोड को सरल और आसान बनाता है अंत में अनुसरण करने के लिए।

1

मुझे लगता है कि यह समझना महत्वपूर्ण है कि अगर हम बाहरी शोर को हटाने और विचार करना सबसे आसान है: है X अंदर

template <typename T> 
struct X 
{ 
    friend void f(X<T>& x) { } 
}; 

template <typename T> 
void f(const X<T>& x) { } 
  • f: void f(X<T>& x)
  • f बाहर X है: void f<T>(X<T>& x)

आप टी को संकलित और देखकर इसका संकेत प्राप्त कर सकते हैं वह प्रतीकों उत्पन्न:

00410aa8 t .text$_Z1fR1XIdE 
00410ad4 t .text$_Z1fIdEvRK1XIT_E 

प्रत्येक पैदावार से जीसीसी के __PRETTY_FUNCTION__ कॉलिंग:

void f(X<double>&) 
void f(const X<T>&) [with T = double] 

विशेष रूप से स्पष्ट नहीं है, लेकिन कहने का जीसीसी के रास्ते उत्तरार्द्ध के void f<double>(...)

व्यक्तिगत रूप से, टेम्पलेट्स के लिए मैं कक्षा में समारोह को परिभाषित करने के लिए करते हैं ... आप, बिल्कुल टेम्पलेट पहलू का उल्लेख बस की जरूरत नहीं है:

friend ostream& operator<<(ostream& os, const Edge& e) 
{ 
    // use e.whatever... 
} 
संबंधित मुद्दे