2015-06-18 8 views
6

पर अलग-अलग व्यवहार का कारण बनता है यह एक और "यह अच्छा कर रहा है?" जीसीसी 6.0.0 और क्लैंग 3.7.0 के बाद से सवाल अलग-अलग व्यवहार करते हैं।एक गैर-प्रकार तर्क के लिए अग्रेषण चरणीय टेम्पलेट

मान लें हम जो गैर टेम्पलेट तर्क के रूप में एक const char * लेता है और किसी दिए गए सूचक के लिए विशेष है एक चर टेम्पलेट करते हैं:

constexpr char INSTANCE_NAME[]{"FOO"}; 

struct Struct{ void function() const { std::cout << __PRETTY_FUNCTION__; } }; 
std::ostream &operator <<(std::ostream &o, const Struct &) { return o << INSTANCE_NAME; } 

template <const char *> char Value[]{"UNKNOWN"}; 
// spezialization when the pointer is INSTANCE_NAME 
template <   > Struct Value<INSTANCE_NAME>{}; 

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

template <const char *NAME> void print() 
{ 
    std::cout << Value<NAME> << '\n'; 
} 

template <const char *NAME> void call_function() 
{ 
    Value<NAME>.function(); 
} 

फिर, बुला अलग व्यवहार में यह कार्यों के परिणाम:

int main() 
{ 
    print<INSTANCE_NAME>(); 
    call_function<INSTANCE_NAME>(); 

    return 0; 
} 

Code Here

बजना 3.7.0 प्रिंट FOO और void Struct::function() const (के रूप में मैं उम्मीद कर रहा था), जबकि जीसीसी 6.0.0 नीचे त्रुटि के साथ संकलित करने के लिए विफल रहता है:

सदस्य 'मान' में 'समारोह', गैर वर्ग प्रकार की है, जिसके लिए अनुरोध 'चार [8]'

मैं लगभग लगता है कि जीसीसी समारोह call_function में चर टेम्पलेट Value करने के लिए टेम्पलेट गैर प्रकार तर्क NAMEआगे करने में विफल रहा है और इस कारण के लिए जो 'char [8]' प्रकार के साथ एक है unspecialized चर टेम्पलेट का चयन करता हूँ ...

यह अभिनय कर रहा है जैसे यह टेम्पलेट तर्क की प्रतिलिपि बना रहा है। यह केवल तब होता है जब ऑब्जेक्ट के सदस्य फ़ंक्शन को कॉल करते हैं, अगर हम call_function के शरीर पर टिप्पणी करते हैं, तो आउटपुट FOOUNKNOWN नहीं है, इसलिए printफ़ॉरवर्डिंग फ़ंक्शन जीसीसी में भी काम कर रहा है।

तो

  • सही व्यवहार क्या है? (मील शर्त clang के लिए है)
  • मैं संकलक के लिए एक बग टिकट कैसे खोल सकता हूं जो गलत कर रहा है?
+0

@ BЈовић आप, जब तक कि 'स्थिरांक चार *' बाहरी संबंध है ([इस जवाब को देखने] (http://stackoverflow.com/a/16402606/499359)) कर सकते हैं। बाहरी संबंध के साथ यह हमेशा एक ही पता होगा; इसके बारे में सोचें जैसे कि यह 'int' था। –

+2

बस एक नोट: 'फू', 'फू' और 'फू' नामक पूरी तरह से अलग संरचनाएं होने से मानसिक रूप से आपके उदाहरण को पार्स करना मुश्किल हो जाता है। 'माईकर्प', 'माईस्ट्रक्चर' और 'मायफन' या इसी तरह का आसान होगा। – TartanLlama

+0

@TartanLlama मैं भी बुला बिना नाम, सुझाव के लिए धन्यवाद :) –

उत्तर

3

एक उचित सहमति है कि चर टेम्पलेट विशेषज्ञताओं चर टेम्पलेट के प्रकार में परिवर्तन करने की अनुमति दी जाती है नहीं है: C++1y/C++14: Variable Template Specialization?

जीसीसी के व्यवहार विशेष रूप से दिलचस्प है अगर Value के डिफ़ॉल्ट प्रकार के साथ एक प्रकार परिवर्तित करने के लिए एक function विधि:

struct Unknown{ void function() const { std::cout << __PRETTY_FUNCTION__; } }; 
template <const char *> Unknown Value; 

prog.cc: In instantiation of 'void call_function() [with const char* NAME = ((const char*)(& INSTANCE_NAME))]': 
prog.cc:26:18: required from here 
prog.cc:20:5: error: 'Unknown::function() const' is not a member of 'Struct' 
    Value<NAME>.function(); 
    ^

बग कि जहां गैर-विशिष्ट चर टेम्पलेट एक प्रकार है कि चर टेम्पलेट टेम्पलेट मापदंडों पर निर्भर नहीं है है, जीसीसी मान लिया गया प्रतीत होता है टेम्पलेट विधियों के भीतर जो उस परिवर्तनीय टेम्पलेट का उपयोग करते हैं कि परिवर्तनीय टेम्पलेट में हमेशा उस प्रकार का होता है।

सामान्य रूप से, वर्कअराउंड, क्लास टेम्पलेट के विशेषज्ञता (ओं) के साथ एक क्लास टेम्पलेट में बिना टेम्पलेट टेम्पलेट को अग्रेषित करना है, और ओडीआर अनुपालन के लिए आवश्यक झुकाव के साथ।

एक और (संभवतः आसान) वर्कअराउंड गैर-विशिष्ट परिवर्तनीय टेम्पलेट प्रकार को किसी भी तरह परिवर्तनीय टेम्पलेट टेम्पलेट पैरामीटर पर निर्भर करना है; आपके मामले में यह काम करेगा:

template <const char *P> decltype(*P) Value[]{"UNKNOWN"}; 

मैं gcc bugzilla में एक इसी मुद्दे नहीं मिल रहा है तो आप कोई नया दर्ज कर सकते हैं। यहां एक न्यूनतम उदाहरण दिया गया है:

struct U { void f() {} }; 
struct V { void f() {} }; 
template<class T> U t; 
template<> V t<int>; 
template<class T> void g() { t<T>.f(); } 
int main() { g<int>(); } 
+0

मैं इस मुद्दे को जोड़ दिया है (आशा है कि मैं यह अच्छी तरह से किया था, सब के बाद मेरा पहला बग रिपोर्ट है) मैं अपने उदाहरण और अपने पाठ का उपयोग किया है (क्योंकि अंग्रेज़ी मेरी पहली भाषा नहीं है और मुझे यकीन है कि अगर मैं लिख रहा था नहीं कर रहा हूँ कुछ अजीब), बहुत बहुत शुक्रिया। –

+0

@PaperBirdMaster अच्छा लग रहा है; मैंने त्रुटि आउटपुट जोड़ा है। https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66596 – ecatmur

5

दिलचस्प बात यह है कि जीसीसी इस उदाहरण में स्वयं विरोधाभासी भी है।

constexpr char NOT_FOO[]{"NOT_FOO"}; 
:

template <typename T> 
struct type_check; 

हम भी एक और const char* है कि हम परीक्षण के लिए उपयोग कर सकते हैं बनाती हूँ:

एक अधूरी टेम्पलेट वर्ग है जो कुछ अच्छा संकलक संदेशों है कि हम दुरुपयोग कर सकते हैं देना चाहिए घोषित की सुविधा देता है

template <const char *NAME> void foo() 
{ 
    type_check<decltype(Value<FOO>)> a; 
    type_check<decltype(Value<NAME>)> b; 
    type_check<decltype(Value<NOT_FOO>)> c; 
    type_check<decltype(Value<FOO>.foo())> d; 
    type_check<decltype(Value<NAME>.foo())> e; 
    type_check<decltype(Value<NOT_FOO>.foo())> f; 
} 

एच:

अब हम क्या संकलक पर chokes देखेंगे पहले त्रुटियाँ जो जीसीसी 5.1.0 का उत्पादन (स्पष्टता के लिए एक सा संपादित) कर रहे हैं:

test.cpp:21:38: error: ‘type_check<Foo> a’ has incomplete type 
    type_check<decltype(Value<FOO>)> a; 
            ^
test.cpp:22:39: error: ‘type_check<Foo> b’ has incomplete type 
    type_check<decltype(Value<NAME>)> b; 

test.cpp:25:42: error: ‘type_check<char [8]> c’ has incomplete type 
    type_check<decltype(Value<NOT_FOO>)> c; 
            ^
test.cpp:23:44: error: ‘type_check<void> c’ has incomplete type 
    type_check<decltype(Value<FOO>.foo())> c; 

test.cpp:24:37: error: request for member ‘foo’ in ‘Value<NAME>’, which is of non-class type ‘char [8]’ 
    type_check<decltype(Value<NAME>.foo())> d; 

test.cpp:28:40: error: request for member ‘foo’ in ‘Value<((const char*)(& NOT_FOO))>’, which is of non-class type ‘char [8]’ 
    type_check<decltype(Value<NOT_FOO>.foo())> f; 

के एक समय में इन एक लेते हैं।


त्रुटि 1:

test.cpp:21:38: error: ‘type_check<Foo> a’ has incomplete type 
    type_check<decltype(Value<FOO>)> a; 

पहले त्रुटि में, हम देख सकते हैं जीसीसी सही ढंग से deduces कि कि Value<FOO> के प्रकार Foo है। हम यही उम्मीद करते हैं।

त्रुटि 2:

test.cpp:22:39: error: ‘type_check<Foo> b’ has incomplete type 
    type_check<decltype(Value<NAME>)> b; 

यहाँ, जीसीसी सही ढंग से अग्रेषण करता है और बाहर काम करता है कि Value<NAME> प्रकार Foo की है।

त्रुटि 3:

test.cpp:25:42: error: ‘type_check<char [8]> c’ has incomplete type 
    type_check<decltype(Value<NOT_FOO>)> c; 

बढ़िया है, Value<NOT_FOO>"UNKNOWN" है, इसलिए यह सही है।

त्रुटि 4:

test.cpp:23:44: error: ‘type_check<void> c’ has incomplete type 
    type_check<decltype(Value<FOO>.foo())> c; 

यह ठीक है, Value<FOO>Foo है, जो हम पर foo कॉल कर सकते हैं, void लौटने।

त्रुटि 5:

test.cpp:24:37: error: request for member ‘foo’ in ‘Value<NAME>’, which is of non-class type ‘char [8]’ 
    type_check<decltype(Value<NAME>.foo())> d; 

यह अजीब एक है। भले ही त्रुटि 2 में हम देख सकें कि जीसीसी जानता है कि Value<NAME> का प्रकार Foo है, जब यह foo फ़ंक्शन के लिए लुकअप करने का प्रयास करता है, तो यह गलत हो जाता है और इसके बजाय प्राथमिक टेम्पलेट का उपयोग करता है। यह फ़ंक्शन लुकअप में कुछ बग हो सकता है जो गैर-प्रकार के टेम्पलेट तर्कों के मानों को सही ढंग से हल नहीं करता है।

त्रुटि 6:

test.cpp:28:40: error: request for member ‘foo’ in ‘Value<((const char*)(& NOT_FOO))>’, which is of non-class type ‘char [8]’ 
    type_check<decltype(Value<NOT_FOO>.foo())> f; 

यहाँ हम जब बाहर काम कर क्या Value<NOT_FOO> है संकलक सही ढंग से प्राथमिक टेम्पलेट चुन देख सकते हैं। जो चीज़ मुझे रूचि देती है वह (const char*)(& NOT_FOO)) है जो जीसीसी NOT_FOO के प्रकार के रूप में deduces। शायद यह इस मुद्दे के लिए एक सूचक है? मुझे यकीन नहीं है।


मैं एक बग दर्ज करने और विसंगति को इंगित करने का सुझाव दूंगा। शायद यह आपके प्रश्न का पूरी तरह से जवाब नहीं देता है, लेकिन मुझे आशा है कि इससे मदद मिलती है।

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