क्या यह कोड C++17 में संकलित करने में विफल होना चाहिए?



clang boost-variant (1)

मैं C ++ 17 का उपयोग करने के लिए एक परियोजना को अपडेट कर रहा था और कुछ उदाहरण मिले जहां इस पैटर्न का पालन करने वाले कोड क्लैंग के हाल के संस्करणों पर एक संकलन त्रुटि पैदा कर रहे थे:

#include <boost/variant.hpp>

struct vis : public boost::static_visitor<void>
{
    void operator()(int) const { }
};

int main()
{
    boost::variant<int> v = 0;
    boost::apply_visitor(vis{}, v);
}

C ++ 17 मोड में clang v8.0 का उपयोग करना, यह निम्न त्रुटि के साथ विफल होता है :

<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
    boost::apply_visitor(vis{}, v);
                             ^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
    ~static_visitor() = default;

हालाँकि, यह C ++ 14 मोड में सफाई से संकलित करता है । मैंने पाया कि अगर मैं कोष्ठक आरंभीकरण vis{} को कोष्ठक vis() बदलता हूं, तो यह दोनों मोड में सही ढंग से संकलित करता है। Gcc का हर संस्करण जिसे मैंने आज़माया है, दोनों प्रकारों को C ++ 17 मोड में अनुमति देता है।

क्या यह C ++ 14 से C ++ 17 के व्यवहार में एक सही बदलाव है, या यह एक क्लैंग बग है? यदि यह सही है, तो यह अब C ++ 17 में अमान्य क्यों है (या शायद यह हमेशा था, लेकिन क्लैंग सिर्फ इसे पहले के मानक संशोधन में अनुमति देता है)?


क्लेंग यहीं है। यहाँ एक कम उदाहरण है:

struct B {
protected:
    B() { }
};

struct D : B { };

auto d = D{};

C ++ 14 में, D एक समुच्चय नहीं है क्योंकि इसका आधार वर्ग है, इसलिए D{} "सामान्य" (गैर-समुच्चय) आरंभीकरण है, जो D के डिफ़ॉल्ट कंस्ट्रक्टर को आमंत्रित करता है, जो बदले में B के डिफ़ॉल्ट कंस्ट्रक्टर को आमंत्रित करता है। यह ठीक है, क्योंकि D की B के डिफ़ॉल्ट कंस्ट्रक्टर तक पहुंच है।

सी ++ 17 में, कुल की परिभाषा को चौड़ा किया गया था - आधार वर्गों को अब अनुमति दी गई है (जब तक वे गैर- virtual )। D अब एक एग्रीगेट है, जिसका अर्थ है कि D{} एग्रीगेट इनिशियलाइज़ेशन है। और समग्र-आरंभीकरण में, इसका मतलब है कि हम (कॉलर) बेस क्लास सबोबिज सहित - सभी सबोबिज को इनिशियलाइज़ कर रहे हैं। लेकिन हमारे पास B के निर्माता तक पहुंच नहीं है (यह protected ), इसलिए हम इसे लागू नहीं कर सकते, इसलिए यह बीमार है।

डर नहीं, तय करना आसान है। कोष्ठक का प्रयोग करें:

auto d = D();

यह पहले की तरह D के डिफॉल्ट कंस्ट्रक्टर को वापस करने के लिए जाता है।





boost-variant