2017-08-22 22 views
15

मैं एक वर्ग इस तरह परिभाषित किया गया है:विरासत में प्राप्त कंस्ट्रक्टर्स उपेक्षा इन-क्लास प्रारंभ

class ASTConcatenateLiteral : public ASTExpr { 
    using ASTExpr::ASTExpr; 
private: 
    Type type_ = Type::nothingness(); // Type does not have a default constructor 
}; 

यह बजना के साथ ठीक काम करता है। जीसीसी, हालांकि, मुझे लगता है कि यह डिफ़ॉल्ट प्रारंभकर्ता उपयोग करने के लिए कोशिश कर रहा है कि बनाता है एक त्रुटि संदेश देता है:

error: no matching function for call to ‘EmojicodeCompiler::Type::Type()’

अगर मैं इस तरह एक सार्वजनिक निर्माता के साथ using ASTExpr::ASTExpr; की जगह (ASTExpr केवल वास्तव में इस निर्माता प्रदान करता है)

ASTConcatenateLiteral(const SourcePosition &p) : ASTExpr(p) {} 

सबकुछ ठीक काम करता है।

cppreference.com के अनुसार:

The inherited constructors are equivalent to user-defined constructors with an empty body and with a member initializer list consisting of a single nested-name-specifier, which forwards all of its arguments to the base class constructor.

तो क्यों नहीं है विरासत में मिला निर्माता काम करता है? यदि विरासत वाला कन्स्ट्रक्टर उपयोगकर्ता द्वारा परिभाषित कन्स्ट्रक्टर की तरह व्यवहार करता है, तो इसे type_ के लिए प्रदान किए गए मान का उपयोग करना चाहिए, है ना? मानक के अनुसार कौन सा कंपाइलर्स सही है?

+3

यह g ++ 7.2 के साथ ठीक संकलित करता है। – Holt

+0

@ होल्ट शीश। कोई आश्चर्य नहीं कि मैंने समस्या को पुन: उत्पन्न करने का प्रबंधन नहीं किया है, अगर यह केवल पुराने संस्करणों में विफल रहता है। – hvd

+0

@ होल्ट मैंने 6.2.0 के साथ प्रयास किया। लेकिन उस मामले में मुझे एक बार फिर से जीसीसी संस्करण की आवश्यकता को टक्कर लाना होगा ... – idmean

उत्तर

15

क्लैंग सही है। जब inherited constructor का उपयोग किया जाता है, तो आरंभिकता आगे बढ़नी चाहिए जैसे कि डिफॉल्ट डिफॉल्ट कन्स्ट्रक्टर का उपयोग व्युत्पन्न वर्ग के ऑब्जेक्ट को प्रारंभ करने के लिए किया गया था, इस प्रकार default member initializers का उपयोग किया जाना चाहिए।

(जोर मेरा)

If overload resolution selects one of the inherited constructors when initializing an object of such derived class, then the Base subobject from which the constructor was inherited is initialized using the inherited constructor, and all other bases and members of Derived are initialized as if by the defaulted default constructor (default member initializers are used if provided, otherwise default initialization takes place).

यहाँ standard से एक उदाहरण है:

struct B1 { 
    B1(int, ...) { } 
}; 

struct B2 { 
    B2(double) { } 
}; 

int get(); 

struct D1 : B1 { 
    using B1::B1;  // inherits B1(int, ...) 
    int x; 
    int y = get(); 
}; 

void test() { 
    D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4), 
        // then d.x is default-initialized (no initialization is performed), 
        // then d.y is initialized by calling get() 
    D1 e;    // error: D1 has a deleted default constructor 
} 

ध्यान दें कि d.y डिफ़ॉल्ट सदस्य प्रारंभकर्ता से आरंभ नहीं हो जाता।

12

यह जीसीसी डेवलपर्स द्वारा एक कंपाइलर बग, PR67054 के रूप में माना जाता था, जिसे जीसीसी 7.2 में तय किया गया था।

Their minimal example

struct A 
{ 
    A(int) {} 
}; 

struct C 
{ 
    C(int) {} 
}; 

struct B : A 
{ 
    using A::A; 
    C c = 42; 
}; 

int main() 
{ 
    B b = 24; 
} 

ऑनलाइन compilers कि जीसीसी सत्यापित करने के लिए इस्तेमाल किया जा सकता और बजना समझौते में अब कर रहे हैं है।

ध्यान दें कि जीसीसी 7.1 में, जहां तक ​​मैं कह सकता हूं, कोई गलत कोड उत्पन्न नहीं होगा। हालांकि कंपाइलर को एक डिफ़ॉल्ट कन्स्ट्रक्टर की आवश्यकता होती है, लेकिन डिफ़ॉल्ट कन्स्ट्रक्टर कभी नहीं कहा जाएगा। इसलिए, जीसीसी के पुराने संस्करणों के लिए एक संभावित कार्यवाही डिफ़ॉल्ट कन्स्ट्रक्टर की घोषणा प्रदान कर रही है, लेकिन परिभाषा नहीं है। शायद इसका उपयोग करने के किसी भी प्रयास को अस्वीकार करने के लिए एक विशेषता (मानक सी ++ नहीं) का उपयोग करें:

struct C 
{ 
#ifdef GCC_WORKAROUND_PR67054 
    C() __attribute__((__error__("No."))); 
#endif 
    C(int) {} 
}; 
संबंधित मुद्दे