2015-10-15 5 views
24

मेरे पास निम्न कोड है जो g ++ के अंतर्गत संकलित करता है, लेकिन क्लैंग के साथ नहीं।क्या यह वैध सी ++ 11

क्लैंग कोड को संकलित करेगा यदि विभिन्न मामूली तरीकों से बदल दिया गया है, जैसे 2 नामस्थान घोषणाओं को विलय करना। उबंटू कोर 15.04 पर

g++ -fsyntax-only -std=c++11 testcase.cpp 

संस्करण हैं जी ++ 4.9.2, बजना 3.6.0, दोनों:

// The problem disappears without namespaces. 
namespace Root { 
    // The problem disappears if 'g' is in the global namespace, and we change 
    // the friend declaration to '::g' 

    // The problem disappears if 'g' has void return type. 

    // The problem disappears if we get rid of the 'Value' template argument 
    // and the 'value' parameter. 
    template<typename Value, typename Defaulted = void> 
    bool g(Value value); 

    // The problem disappears if MyClass is not a template. 
    template<typename ClassValue> 
    class MyClass { 
    private: 
     template<typename Value, typename Defaulted> 
     friend bool g(Value value); 
    }; 
} 

// The problem disappears if we declare the Root namespace in a single block 
// containing 'g', 'MyClass' and 'f'. 

// The problem remains if we declare f in the global namespace and reference 
// Root::g. 
namespace Root { 
    void f() { 
     MyClass<int> value; 

     g(value); 
    } 
} 

बजना के साथ संकलन करने के लिए:

clang -fsyntax-only -std=c++11 testcase.cpp 

जी के साथ ++ संकलन करने के लिए। मेरा मानना ​​है कि यह एक बजना बग है

testcase.cpp:24:9: error: no matching function for call to 'g' 
     g(value); 
     ^
testcase.cpp:14:21: note: candidate template ignored: couldn't infer template argument 'Defaulted' 
     friend bool g(Value value); 
       ^
1 error generated. 
+0

दोस्त समारोह (भले ही एक वर्ग में घोषित) नाम स्थान गुंजाइश है:

का संभावित हल बस दोस्त को विशेषज्ञता हम के बारे में परवाह नहीं होगा। तो इस मामले में आपके पास 'बूल रूट :: जी() 'के लिए 2 फ़ंक्शन घोषणाएं हैं। टेम्पलेट पैरामीटर घोषणा नहीं बदलते हैं। यही कारण है कि आपके मामूली परिवर्तन इस कोड को काम करते हैं। मैं वास्तव में और अधिक हैरान हूं कि यह g ++ के साथ संकलित है। –

+3

@ सिमोनक्रैमर आपको कई बार फ़ंक्शन घोषित करने की अनुमति है। और 'मित्र' घोषणा वैसे भी समारोह को फिर से शुरू नहीं करेगा। – Barry

+0

क्या यह आपका पूरा कोड या सिर्फ प्रासंगिक हिस्सा है? –

उत्तर

7

:

बजना त्रुटि संदेश देता है। से [temp.param], हमने:

एक दोस्त समारोह टेम्पलेट घोषणा निर्दिष्ट करता है एक डिफ़ॉल्ट टेम्पलेट तर्क, उस घोषणा एक परिभाषा होगी और में समारोह टेम्पलेट का केवल घोषणा की जाएगी अनुवाद इकाई।

डिफ़ॉल्ट टेम्पलेट तर्क उपयोग के लिए उपलब्ध का सेट उसी तरह डिफ़ॉल्ट समारोह तर्क में टेम्पलेट के सभी पूर्व घोषणाओं से डिफ़ॉल्ट तर्क मर्ज करके प्राप्त किया जाता है कर रहे हैं (8.3.6)।

उत्तरार्द्ध बिंदु मतलब है कि हम लिख सकते हैं:

template <typename T, typename U=int> 
void h(); 

template <typename T, typename U> 
void h() { } 

h<int>(); 

और यह पूरी तरह से अच्छी तरह से कोड है कि compiles बजना ही बना है। हम रूप g पहले से घोषित किया जाता है, g नियम उद्धृत के आधार पर करने के लिए डिफ़ॉल्ट टेम्पलेट तर्क को निर्दिष्ट नहीं सकते हैं, लेकिन नहीं यह निर्दिष्ट करने के लिए अभी भी Defaulted मर्ज कदम के माध्यम से void के रूप में उपयोग के लिए उपलब्ध रखना चाहिए। यदि डिफ़ॉल्ट-तर्क उपलब्ध है, तो लुकअप g हमें ढूंढने में सक्षम होना चाहिए।

friend bool g<>(MyClass value); 
+0

उलटी गिनती @ टी.सी. मुझे 5 में सुधार रहा है ... 4 ... – Barry

+0

धन्यवाद - मैं विलय के बारे में आप जो कह रहा हूं उससे सहमत हूं, और यह मुझे समझ में आता है। लेकिन मैंने सोचा कि आपको यह निर्दिष्ट करने की अनुमति नहीं है कि किसी मित्र में टेम्पलेट पैरामेट डिफ़ॉल्ट रूप से क्या चूकता है। यह देखते हुए कि, पहले पैराग्राफ की मेरी (गलत) व्याख्या इसलिए होगी: किसी मित्र को टेम्पलेट परम के साथ घोषित करके जिसमें पहले से ही एक डिफ़ॉल्ट (घोषित कहीं और) है, मुझे मित्र घोषणा के साथ फ़ंक्शन बॉडी प्रदान करनी होगी? –

+0

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