2008-09-09 15 views
6

एक दोस्त और मैं सी ++ टेम्पलेट्स पर चर्चा कर रहे थे। उसने मुझसे पूछा कि यह क्या करना चाहिए:सी ++ टेम्पलेट अस्पष्टता

#include <iostream> 

template <bool> 
struct A { 
    A(bool) { std::cout << "bool\n"; } 
    A(void*) { std::cout << "void*\n"; } 
}; 

int main() { 
    A<true> *d = 0; 
    const int b = 2; 
    const int c = 1; 
    new A<b> (c) > (d); 
} 

मुख्य में अंतिम पंक्ति में दो उचित पार्स हैं। टेम्पलेट तर्क 'बी' है या b > (c) टेम्पलेट तर्क है?

हालांकि, यह संकलित करने के लिए तुच्छ है, और देखें कि हमें क्या मिलता है, हम सोच रहे थे कि अस्पष्टता क्या हल करती है?

उत्तर

5

AFAIK इसे new A<b>(c) > d के रूप में संकलित किया जाएगा। आईएमएचओ को पार्स करने का यह एकमात्र उचित तरीका है। यदि पार्सर सामान्य परिस्थितियों में नहीं आ सकता है तो> एक टेम्पलेट तर्क समाप्त करें, जिसके परिणामस्वरूप यह अधिक अस्पष्टता होगी। आप इसे दूसरी तरह चाहते हैं, आप लिखा जाना चाहिए था:

new A<(b > c)>(d); 
0

लेक्सर की लालची शायद इसे स्पष्ट करने के लिए कोष्ठक की अनुपस्थिति में निर्धारित कारक है। मुझे लगता है कि लेजर लालची नहीं है।

+0

लेकिन lexing पूरी तरह से स्पष्ट नहीं है? –

+0

यह अस्पष्टता पर त्रुटि होगी, इसलिए हां। लालची या गैर लालची होने से आपको अस्पष्ट नहीं होता है। लालची वास्तव में अस्पष्टता को हल करने का एक तरीका है। आप इस मामले में लेक्सर और पार्सर के बीच बातचीत में भी आते हैं, तो शायद यह पार्सर है जो लालची नहीं है। –

+0

व्याकरण संदिग्ध हो सकता है, लेकिन लेक्सर बिल्कुल नहीं है। अंतराल लेक्सर को पूरी तरह से परिभाषित करता है। –

3

सी ++ मानक को परिभाषित करता है, तो एक टेम्पलेट का नाम एक < द्वारा पीछा के लिए, < हमेशा टेम्पलेट तर्क सूची की शुरुआत और पहली गैर है कि -निस्टेड > टेम्पलेट तर्क सूची के अंत के रूप में लिया जाता है।

यदि आप इरादा रखते हैं कि > ऑपरेटर का परिणाम टेम्पलेट तर्क हो, तो आपको अभिव्यक्ति को कोष्ठक में संलग्न करना होगा। यदि तर्क static_cast<> या अन्य टेम्पलेट अभिव्यक्ति का हिस्सा था तो आपको कोष्ठक की आवश्यकता नहीं है।

6

जैसा कि लियोन & ली द्वारा बताया गया है, 14.2/3 (सी ++ '03) स्पष्ट रूप से इस व्यवहार को परिभाषित करता है।

सी ++ '0x >> पर लागू होने वाले समान नियम के साथ मज़े में जोड़ता है। मूल अवधारणा यह है कि जब एक टेम्पलेट तर्क-सूची को पार्स एक गैर नेस्टेड >> और दो अलग-अलग >> टोकन रूप में माना जाएगा न सही पारी ऑपरेटर है:

template <bool> 
struct A { 
    A(bool); 
    A(void*); 
}; 

template <typename T> 
class C 
{ 
public: 
    C (int); 
}; 

int main() { 
    A<true> *d = 0; 
    const int b = 2; 
    const int c = 1; 
    new C <A<b>> (c) > (d); // #1 
    new C <A<b> > (c) > (d); // #2 
} 

'# 1' और '# 2' उपरोक्त में बराबर हैं।

बेशक यह नेस्टेड विशेषज्ञताओं में रिक्त स्थान को जोड़ने के लिए होने के साथ फिक्स कि झुंझलाहट:

C<A<false>> c; // Parse error in C++ '98, '03 due to "right shift operator" 
+0

मैंने इससे पहले सुना है। कुछ कंपाइलर्स ने 'x >' वैसे भी अनुमति देकर बंदूक कूद दी है। लेकिन मैं बस सोच रहा हूं: क्या यह वास्तव में संदर्भ-संवेदनशील लेक्सिंग के संदर्भ में परिभाषित किया गया है, या एक व्याकरण नियम जैसे टेम्पलेटआईड '<' टेम्पलेटआईडी '<' टेम्पलेटएर्गमेंट '>>' अपने अधिकार में दिया गया है? – Stewart

+1

@ स्टीवर्ट: यह पूर्व (संदर्भ-संवेदनशील लेक्सिंग) है। संक्षेप में, 14.2/3 कहता है कि टेम्पलेट-तर्क-सूची को पार्स करते समय पहली गैर-नेस्टेड >> को दो अलग> टोकन के रूप में माना जाता है। आप अधिक जानकारी के लिए वास्तविक पेपर पढ़ सकते हैं: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html –

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