2013-06-27 14 views
10

के साथ स्वैप अजीबता यह एक अजीबता है, जहां मुझे नहीं पता, अगर यह सी ++ मानक के साथ है, तो मेरे कंपाइलर (उबंटू 12.04 पर जी ++ संस्करण 4.6.3, जो कि नवीनतम दीर्घकालिक है)std :: G ++

#include <algorithm> // for std::swap 
void f(void) 
{ 
    class MyClass { }; 
    MyClass aa, bb; 
    std::swap(aa, bb);   // doesn't compile 
} 

जब जी ++ के साथ संकलित करने के लिए कोशिश कर रहा है, संकलक पैदावार निम्नलिखित: Ubuntu के समर्थन संस्करण) या मेरे साथ, जो ;-)

नहीं समझती प्रश्न में कोड के रूप में सरल रूप में निम्नानुसार है त्रुटि संदेश:

test.cpp: In function ‘void f()’: 
test.cpp:6:21: error: no matching function for call to ‘swap(f()::MyClass&, f()::MyClass&)’ 
test.cpp:6:21: note: candidates are: 
/usr/include/c++/4.6/bits/move.h:122:5: note: template<class _Tp> void std::swap(_Tp&, _Tp&) 
/usr/include/c++/4.6/bits/move.h:136:5: note: template<class _Tp, long unsigned int _Nm> void std::swap(_Tp (&)[_Nm], _Tp (&)[_Nm]) 

आश्चर्यजनक परिणाम है, बस समारोह से बाहर वर्ग परिभाषा चलती है कि बनाता है कि कोड ठीक संकलन:

#include <algorithm> // for std::swap 
class MyClass { }; 
void f(void) 
{ 
    MyClass aa, bb; 
    std::swap(aa, bb);   // compiles fine! 
} 

तो यह है, कि std :: स्वैप() वर्ग है, जो कर रहे हैं पर काम करने वाला नहीं है कार्यों के लिए निजी? या यह G ++ के साथ एक बग है, शायद मैं G ++ का विशिष्ट संस्करण उपयोग कर रहा हूं?

#include <algorithm>  // for std::swap 
#include <list>    // for std::list 
void g(void) 
{ 
    class MyListClass : public std::list<int> { }; 
    MyListClass aa, bb; 
    std::swap(aa, bb);    // compiles fine! 
} 

:

इससे भी अधिक पेचीदा है कि निम्नलिखित फिर से काम करता है, के बावजूद MyListClass भी निजी है (लेकिन एक "आधिकारिक" वर्ग, शायद स्वैप() की एक विशेष कार्यान्वयन मौजूद है जिसके लिए फैली हुई है) है,

लेकिन ऑब्जेक्ट्स से पॉइंटर्स में बस बदलें, और संकलन फिर से विफल हो जाता है:

#include <algorithm>  // for std::swap 
#include <list>    // for std::list 
void g(void) 
{ 
    class MyListClass : public std::list<int> { }; 
    MyListClass aa, bb; 
    MyListClass* aap = &aa; 
    MyListClass* bbp = &bb; 
    std::swap(aap, bbp); // doesn't compile! 
} 

बेशक, मेरे वास्तविक आवेदन में कक्षाएं अधिक जटिल हैं; मैंने समस्या को फिर से उत्पन्न करने के लिए जितना संभव हो सके कोड को सरल बना दिया।

उत्तर

16

यदि आप सी ++ 03 मोड में चल रहे हैं, जिसे मैं मानता हूं, तो आपको टेम्पलेट में स्थानीय रूप से परिभाषित प्रकार का उपयोग करने की अनुमति नहीं है। यदि ऐसा है तो आप इसे नाम बनाने के लिए नामस्थान स्तर पर अपने प्रकार परिभाषित कर सकते हैं, अन्यथा आप सी ++ 11 मोड में संकलित कर सकते हैं जहां इसे संकलित करना चाहिए। [*]

यदि आपको आश्चर्य है कि दूसरा मामला क्यों है काम करता है, मानक

template <typename T> void swap(T&,T&) // [1] 
std::list रूप

की विशेषज्ञता प्रदान नहीं करता है एक टेम्पलेट ही है और आप आंशिक रूप से टेम्पलेट कार्यों विशेषज्ञ नहीं कर सकते। क्या यह प्रदान करता है एक अलग आधार टेम्पलेट है:

template <typename T, typename A> void swap(list<T,A>&,list<T,A>&); // [2] 

अब पिछले मामले में के रूप में, संकलक के साथ [1], ताकि त्याग दिया जाता है अपने स्थानीय प्रकार का उपयोग नहीं कर सकते हैं। फिर यह कोशिश करता है [2], और यह पाया जाता है कि यह स्थानीय प्रकार के लाल्व को आधार std::list<int> के संदर्भ में परिवर्तित कर सकता है, और उस रूपांतरण के बाद [2] एक अच्छा उम्मीदवार है। यह तो

std::swap(static_cast<std::list<int&>>(aa),static_cast<std::list<int&>>(bb)); 

जो एक स्थानीय प्रकार का उपयोग नहीं करता फोन करेगा, बल्कि नाम स्थान स्तर std::list<int>

दूसरी तरफ, यह संकलित करने वाला तथ्य यह नहीं है कि यह वही करता है जो आप चाहते हैं। विशेष रूप से, यदि विस्तारित प्रकार MyListClass कोई नया सदस्य चर जोड़ता है, तो नहीं बदला जाएगा।

यह सब कहा जा रहा है, और एक साइड नोट के रूप में: आपको मानक कंटेनर से उत्तराधिकारी नहीं होना चाहिए, क्योंकि उन्हें कभी विरासत में शामिल नहीं किया गया था।

[*] अस्वीकरण: मुझे नहीं पता कि यह सुविधा कंपाइलर के उस विशेष संस्करण में समर्थित है या नहीं, आपको दोबारा जांच करनी होगी।

+1

[अपाचे विकी] के अनुसार (http://wiki.apache.org/stdcxx/C%2B%2B0xCompilerSupport), जीसीसी 4.5 के बाद से इसका समर्थन करता है, इसलिए यह विकल्प '-std = c + जोड़ने के लिए पर्याप्त होना चाहिए + 0x'। – Angew

+0

आपके उत्तरों के लिए बहुत बहुत धन्यवाद! जोड़ना -std = C++ 0x स्थानीय वर्गों के साथ भी चीजों को संकलित करता है। वाह, मुझे पुराने सी ++ मानकों में स्थानीय वर्गों और टेम्पलेट्स के साथ असंगतता के बारे में पता नहीं था। –