2016-12-02 10 views
22

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

#include <iostream> 

struct Foo { 
    Foo(int arg) { std::cout << "Foo::Foo(" << arg << ")" << std::endl; } 
}; 

struct Base { 
    Base(int arg) { std::cout << "Base::Base(" << arg << ")" << std::endl; } 
}; 

struct Derived : public Base { 
    using Base::Base; 
    Foo foo{42}; 
}; 

int main() { 
    Derived derived{120}; 
} 

इस कोड को संकलित करता है तथा बजना के साथ अपेक्षित व्यवहार के साथ निष्पादित करता है। जीसीसी के साथ यह संकलन नहीं है, क्योंकि संकलक निर्माता हटाता Derived::Derived(int):

ttt.cpp: In function ‘int main()’: 
ttt.cpp:17:22: error: use of deleted function ‘Derived::Derived(int)’ 
    Derived derived{120}; 
        ^
ttt.cpp:12:15: note: ‘Derived::Derived(int)’ is implicitly deleted because the default definition would be ill-formed: 
    using Base::Base; 
      ^
ttt.cpp:12:15: error: no matching function for call to ‘Foo::Foo()’ 
ttt.cpp:4:3: note: candidate: Foo::Foo(int) 
    Foo(int arg) { std::cout << "Foo::Foo(" << arg << ")" << std::endl; } 
^
ttt.cpp:4:3: note: candidate expects 1 argument, 0 provided 
ttt.cpp:3:8: note: candidate: constexpr Foo::Foo(const Foo&) 
struct Foo { 
     ^
ttt.cpp:3:8: note: candidate expects 1 argument, 0 provided 
ttt.cpp:3:8: note: candidate: constexpr Foo::Foo(Foo&&) 
ttt.cpp:3:8: note: candidate expects 1 argument, 0 provided 

मैं इस तरह Foo के लिए एक डिफ़ॉल्ट निर्माता जोड़ते हैं:

Foo() { std::cout << "Foo::Foo()" << std::endl; }; 

भी जीसीसी यह संकलन कर सकते हैं। कोड बिल्कुल उसी तरह व्यवहार करता है, विशेष रूप से फू के अतिरिक्त डिफॉल्ट कन्स्ट्रक्टर को निष्पादित नहीं किया जाता है।

तो मेरा सवाल अब है, क्या यह वैध सी ++ 11 है? यदि हां, तो शायद मुझे जीसीसी में एक बग मिला है। अन्यथा, क्या gcc और clang दोनों को एक त्रुटि संदेश नहीं देना चाहिए कि यह वैध C++ 11 मान्य नहीं है?

प्रश्न के बाद संपादित करें @ vlad-from-moscow द्वारा अच्छी तरह से उत्तर दिया गया था: यह बग जीसीसी 6.2 में भी मौजूद है, इसलिए मैं एक बग रिपोर्ट दर्ज करूंगा।

2 संपादित करें: वहां पहले से ही एक बग, जो मैं पहले खोज में नहीं मिला है: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67054

+0

मुझे cppreference.com जैसे पृष्ठों पर इसके बारे में कुछ भी नहीं मिल रहा है। "उपयोग" वाक्यविन्यास और ब्रेस प्रारंभकर्ता दोनों का वर्णन किया गया है, लेकिन दोनों को संयोजन के बारे में कुछ भी उल्लेख नहीं किया गया है। –

उत्तर

10

जीसीसी सी संतुष्ट नहीं करता ++ स्टैंडर्ड। व्युत्पन्न वर्ग के उत्तराधिकारी कन्स्ट्रक्टर को बेस कन्स्ट्रक्टर को अपनी यादगार प्रारंभकर्ता सूची में व्युत्पन्न विरासत वाले कन्स्ट्रक्टर के लिए निर्दिष्ट तर्क के साथ कॉल करना चाहिए।

वहाँ सी ++ स्टैंडर्ड में लिखा है (12.9 विरासत निर्माता)

एक वर्ग के लिए 8 एक इनहेरिट निर्माता परोक्ष डी फाई नेड जब यह ओडीआर से इस्तेमाल किया है (3.2) अपने वर्ग प्रकार का ऑब्जेक्ट बनाने के लिए है (1.8)। एक परोक्ष-de फाई निर्माता इनहेरिट नेड वर्ग के initializations कि एक मेम-प्रारंभकर्ता-सूची जिसका केवल मेम-प्रारंभकर्ता साथ उस वर्ग के लिए एक उपयोगकर्ता के प्रश्न के लिखित इनलाइन निर्माता द्वारा किया जाना होगा के सेट करता है एक मेम-प्रारंभकर्ता है -जब नाम का उपयोग करते हुए नेस्टेड-नाम-विशिष्टता में अभिव्यक्ति-सूची से नीचे निर्दिष्ट है, और जहां उसके फ़ंक्शन बॉडी में कंपाउंड-स्टेटमेंट खाली है (12.6.2) । यदि वह उपयोगकर्ता-लिखित कन्स्ट्रक्टर खराब हो जाएगा, तो प्रोग्राम खराब गठित है। अभिव्यक्ति सूची में प्रत्येक अभिव्यक्ति static_cast (पी) के रूप में है, जहां पी संबंधित कन्स्ट्रक्टर पैरामीटर का नाम है और टी घोषित प्रकार पी है।

अनुभाग के अनुसार (12.6।2 ठिकानों और सदस्यों)

8 शुरु कर रहा है एक गैर सौंपने के निर्माता में, यदि एक गैर स्थैतिक डेटा सदस्य या आधार वर्ग दिए गए एक मेम-प्रारंभकर्ता-आईडी ( मामले सहित द्वारा नामित नहीं किया गया है जहां कोई मेम-प्रारंभकर्ता-सूची क्योंकि निर्माता Noctor-प्रारंभकर्ता है) और इकाई का एक आभासी आधार वर्ग एक अमूर्त वर्ग (10.4), तो

नहीं है - अगर इकाई एक गैर स्थिर डेटा सदस्य है कि ब्रेस-या-बराबर-प्रारंभकर्ता है, इकाई को 8.5 में निर्दिष्ट के रूप में प्रारंभ किया गया है;

+0

@VladfromMoscow: मुद्दा इतना नहीं है कि 'व्युत्पन्न (120) 'बेस (120)' को कॉल नहीं करता है और यह भी गलत है कि यह अभिव्यक्ति-सूची मान लेता है 'foo()' (जो अमान्य है) एक प्रारंभकर्ता प्रदान किया जाता है और वास्तविक कॉल 'foo (42)' होगा। यदि आप 'foo' डेटा सदस्य को हटाते हैं, तो gcc कोड स्वीकार करता है। –

+0

@MaththieuM। मैंने अपना जवाब जोड़ दिया है। हालांकि मैंने पाया कि मानक के विभिन्न संस्करणों के बीच विरोधाभास हैं। –

5

ऐसा लगता है कि तुम सही हो, वहाँ जीसीसी

में एक बग §12.9 से है [ class.inhctor]:

एक का उपयोग कर-घोषणा (7.3.3) कि नाम एक निर्माता परोक्ष इनहेरिट कंस्ट्रक्टर्स का एक सेट की घोषणा की। वर्ग Xका उपयोग कर-घोषणा में नाम से विरासत में मिला कंस्ट्रक्टर्स की उम्मीदवार सेट के रूप में निम्नानुसार वास्तविक निर्माणकर्ता और काल्पनिक कंस्ट्रक्टर्स कि डिफॉल्ट पैरामीटर के परिवर्तन से परिणाम के होते हैं:

  • सभी गैर X

के टेम्पलेट कंस्ट्रक्टर्स तो इसका मतलब है कि आपके Derived वर्ग रों निश्चित रूप से अपने आधार से एक निर्माता बन सकता है जो int स्वीकार करता है। इन-क्लास सदस्य प्रारंभिकरण के सामान्य नियमों के बाद, Derived का उदाहरण बनाना Foo के लिए डिफ़ॉल्ट कन्स्ट्रक्टर के बिना कोई समस्या नहीं होनी चाहिए क्योंकि इसका उपयोग नहीं किया जा रहा है। इसलिए, जीसीसी में एक बग है: निर्माता द्वारा

§13.3.1.3 प्रारंभ [over.match.ctor]

जब वर्ग प्रकार की वस्तुओं डायरेक्ट-प्रारंभ कर रहे हैं (8.5) [...], अधिभार संकल्प निर्माता का चयन करता है।प्रत्यक्ष-प्रारंभिकरण के लिए, उम्मीदवार फ़ंक्शंस प्रारंभ करने वाले ऑब्जेक्ट के वर्ग के सभी निर्माता हैं।

तो निर्माता Foo::Foo(int) का चयन किया जाना चाहिए था, जो स्पष्ट रूप से जीसीसी में नहीं था।


एक सवाल मैं पढ़ यह था के बाद किया था "इस के लिए Derived हटाए जाने के लिए डिफ़ॉल्ट निर्माता का कारण है?" जवाब न है।

सुविधाजनक, मानक इस अंश नीचे एक उदाहरण (मैं excising कर रहा हूँ की जरूरत नहीं है क्या) प्रदान करता है: है

struct B1 { 
    B1(int); 
}; 

struct D1 : B1 { 
    using B1::B1; 
}; 

D1 में मौजूद कंस्ट्रक्टर्स के सेट [जोर मेरा]

  • D1(), निहित रूप से घोषित डिफ़ॉल्ट कन्स्ट्रक्टर, ओआरडी-प्रयुक्त
  • 0 बीमार गठित
  • D1(const D1&), परोक्ष-घोषित प्रतिलिपि निर्माता,
  • D1(D1&&) विरासत में मिला नहीं, परोक्ष-घोषित चाल निर्माता,
  • D1(int) विरासत में मिला नहीं, परोक्ष-घोषित उत्तराधिकारी निर्माता
+2

इसका व्युत्पन्न या आधार के डिफ़ॉल्ट कन्स्ट्रक्टर से कोई लेना देना नहीं है। जीसीसी को फू के डिफॉल्ट कन्स्ट्रक्टर की आवश्यकता होती है, लेकिन यह वास्तव में इसे कभी भी कॉल नहीं करती है। –

+0

@ मार्टिनहेयरहोल्जर: आपने कहा "यह कोड क्लैंग के साथ अपेक्षित व्यवहार के साथ संकलित और निष्पादित करता है। जीसीसी के साथ यह संकलित नहीं होता है, क्योंकि संकलक व्युत्पन्न के निर्माता को हटा देता है:"। यह गलत जीसीसी व्यवहार है, और मैं यहां क्या संबोधित कर रहा हूं। आपको और कुछ करने की आवश्यकता नहीं है। – AndyG

+1

आपके संपादन का जिक्र करते हुए: यह अभी भी इस बारे में नहीं है कि व्युत्पन्न का डिफ़ॉल्ट कन्स्ट्रक्टर हटा दिया गया है या नहीं। मुझे व्युत्पन्न के डिफ़ॉल्ट कन्स्ट्रक्टर में दिलचस्पी नहीं है, इसका कभी भी उपयोग नहीं किया जाता है और जीसीसी ने इसे कभी नहीं होने के बारे में शिकायत की है। इसके बजाए, जीसीसी वांछित कन्स्ट्रक्टर डेरिव :: व्युत्पन्न (int) हटा देता है, क्योंकि फू का डिफ़ॉल्ट कन्स्ट्रक्टर मौजूद नहीं है! –

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