2016-05-14 10 views
7

यह न्यूनतम कार्यक्रमlambdas, स्थानीय प्रकार, और वैश्विक नामस्थान

template <typename X> 
void foo (X x) 
{ 
    bar (x); 
} 

template <typename X> 
void bar (X x) 
{ 
} 

int main() 
{ 
    foo ([]{}); 
} 

जीसीसी (4.8.5 और 5.3) के साथ संकलित करता है तथा बजना के साथ संकलित करने के लिए विफल रहता है (3,7)

मेरे विश्लेषण इस प्रकार है के रूप में।

barfoo में प्रयोग किया जाता है और foo के बाद घोषित कर दिया, तो यह foo परिभाषा बिंदु पर दिखाई नहीं देता है। bar पर एकमात्र तरीका foo तत्काल बिंदु तर्क-निर्भर लुकअप के माध्यम से पाया जा सकता है।

foo और bar दोनों का एकमात्र तर्क main में परिभाषित लैम्ब्डा है।

स्पष्ट रूप से जीसीसी वैश्विक नामस्थान में घोषित के रूप में अपने प्रकार का सम्मान करता है, जबकि क्लैंग नहीं करता है। इस प्रकार, जीसीसी एडीएल के माध्यम से bar पा सकता है और क्लैंग नहीं कर सकता है।

int main() 
{ 
    struct K{}; 
    foo (K());  // gcc compiles, clang complains 
} 

ऐसा लगता है कि जीसीसी यहाँ गलत में है: जब हम एक प्रकार main में स्थानीय रूप से परिभाषित का उपयोग

यही बात होता है। मानक के अनुसार लैम्ब्डा का प्रकार अज्ञात (expr.prim.lambda/3) है, इसलिए यह किसी भी नामस्थान से संबंधित नहीं होना चाहिए। माना जाता है कि स्थानीय प्रकार या तो वैश्विक नामस्थान से संबंधित नहीं होना चाहिए।

क्या विश्लेषण सही है? क्या यह ज्ञात जीसीसी बग है?

यह प्रश्न this question से प्रेरित है।

+0

तो, लघु संस्करण "क्या स्थानीय लैम्ब्डा का नाम किसी नामस्थान से संबंधित है, और यदि ऐसा है तो कौन सा?" और एक द्वितीयक अंतर्निहित "फ़ाइल/नेमस्पेस/वर्ग स्कोप पर लैम्ब्डा का प्रकार किसी नामस्थान से संबंधित है, और यदि ऐसा है तो कौन सा?" – Yakk

उत्तर

7

जीसीसी सही है, DR1690/1691 के संकल्प के अनुसार।

[expr.prim.lambda]/4:

बंद प्रकार छोटी से छोटी ब्लॉक गुंजाइश, वर्ग गुंजाइश, या नाम स्थान गुंजाइश है कि इसी लैम्ब्डा अभिव्यक्ति शामिल में घोषित किया जाता है। [नोट: यह नाम प्रकार ([basic.lookup.argdep]) के साथ से जुड़े नामस्थानों और वर्गों का सेट निर्धारित करता है। पैरामीटर प्रकार लैम्ब्डा-घोषणाकर्ता इन संबंधित नामस्थानों और कक्षाओं को प्रभावित नहीं करते हैं। - अंत टिप्पणी]

[basic.lookup.argdep]/2:

तो T, (यूनियनों सहित) एक वर्ग प्रकार है उसके संबंधित वर्ग हैं: वर्ग ही; जिस वर्ग की यह सदस्य है, यदि कोई है; और इसके प्रत्यक्ष और अप्रत्यक्ष आधार वर्ग। इसके संबंधित नामस्थान इसके संबंधित वर्गों के सबसे व्यस्त नामस्थान हैं।

मुद्दे पर बंद प्रकार के निकटतम संलग्न नामस्थान वैश्विक नामस्थान है, इसलिए वैश्विक नामस्थान एक संबंधित नामस्थान है।

+1

हम्म, यह सी ++ 14 में एक नया शब्द जैसा दिखता है। सी ++ 11 ड्राफ्ट की मेरी प्रतिलिपि कहती है * इसके संबंधित नामस्थान ऐसे नामस्थान हैं जिनके संबंधित वर्ग सदस्य हैं। * दोनों कंपाइलर हालांकि -dd = C++ 11 और -std = C++ 14 के साथ समान परिणाम देते हैं। –

+1

@ एनएम। आह, हाँ, http://wg21.link/cwg1690 –

2

जीसीसी यहां गलत है। यह bar() एडीएल के माध्यम से पाता है भले ही []{} वैश्विक नामस्थान का सदस्य नहीं है। एक ही उद्धरण टीसी का उपयोग करना प्रयोग किया है:

[expr.prim.lambda]/4:

बंद प्रकार छोटी से छोटी ब्लॉक गुंजाइश, वर्ग गुंजाइश, या नाम स्थान गुंजाइश है कि इसी लैम्ब्डा अभिव्यक्ति शामिल में घोषित किया जाता है। [नोट: यह नाम प्रकार ([basic.lookup.argdep]) के साथ से जुड़े नामस्थानों और वर्गों का सेट निर्धारित करता है। पैरामीटर प्रकार लैम्ब्डा-घोषणाकर्ता इन संबंधित नामस्थानों और कक्षाओं को प्रभावित नहीं करते हैं। - अंत टिप्पणी]

यह जानबूझकर एक त्रुटि शुरू करने से इस देखना आसान है। जीसीसी में:

auto f = -[]{}; 

int main() 
{ 
    foo (f); 
} 

error: no match for 'operator-' (operand type is '<lambda()>') 

int main() 
{ 
    foo (-[]{}); 
} 

no match for 'operator-' (operand type is 'main()::<lambda()>') 

दूसरी ओर, अगर हम वैश्विक विस्तार के लिए लैम्ब्डा घोषणा ले जाते हैं, बजना शिकायत नहीं करता है:

auto f = []{}; 

int main() 
{ 
    foo (f); 
} 

FWIW इस जीसीसी के लिए Bug 57433 के रूप में सूचना मिली थी लेकिन यह अपुष्ट है। इसमें कार्यक्रमों के अधिक उदाहरण हैं जिनमें जीसीसी स्वीकार/क्लैंग अस्वीकार करता है।

+0

क्या आपने टीसी के जवाब में दूसरे मानक उद्धरण को पढ़ा है? –

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