मैं एक क्लास टेम्प्लेट के लिए एक कॉपी कंस्ट्रक्टर को लागू करने की कोशिश कर रहा था जो सभी इंस्टेंटेशन को क्लास टेम्प्लेट के एक संस्करण से दूसरे संस्करण में बदलने की अनुमति देता है।

यह निम्नलिखित कोड की ओर ले जाता है

#include <memory>
#include <iostream>

template<bool binary>
class Bar {
private:
    friend class Bar<!binary>;
    std::unique_ptr<int> data;
public:
    Bar(int example) : data(std::make_unique<int>(example)) {

    }

    template<bool value>
    Bar(const Bar<value>& bar) : data(std::make_unique<int>(*bar.data)) {

    }

    //other methods that differ depending on binary value...
};

int main() {
    Bar<false> b1{ 1 };
    Bar<false> b2{ b1 }; //causes compile error
    Bar<true> b3{ b1 }; //works as expected
}

एक अलग प्रकार के कार्यों से निर्माण करना, लेकिन एक ही प्रकार से निर्माण करना एक संकलन समय त्रुटि बताते हुए जारी करता है

Bar::Bar(const Bar &)': हटाए गए फ़ंक्शन को संदर्भित करने का प्रयास

जाहिरा तौर पर जेनेरिक कॉपी कंस्ट्रक्टर को नहीं बुलाया जा रहा है, जिसके कारण मुझे कॉपी कंस्ट्रक्टर को मैन्युअल रूप से लिखना पड़ा, जिससे वर्तमान कोड हो गया।

#include <memory>
#include <iostream>

template<bool binary>
class Bar {
private:
    friend class Bar<!binary>;
    std::unique_ptr<int> data;
public:
    Bar(int example) : data(std::make_unique<int>(example)) {

    }

    Bar(const Bar& bar) : data(std::make_unique<int>(*bar.data)) {

    }

    template<bool value>
    Bar(const Bar<value>& bar) : data(std::make_unique<int>(*bar.data)) {

    }

    //other methods that differ depending on binary value...
};

int main() {
    //all work as expected.
    Bar<false> b1{ 1 };
    Bar<false> b2{ b1 };
    Bar<true> b3{ b1 };
    Bar<true> b4{ b3 }; 
}

यह ध्यान देने योग्य है कि यह मूव कंस्ट्रक्टर, कॉपी असाइनमेंट ऑपरेटर और मूव असाइनमेंट ऑपरेटर के लिए भी आवश्यक है। इस प्रकार, मेरे दो प्रश्न हैं

  1. जेनेरिक कॉपी या मूव कंस्ट्रक्टर कॉपी/मूव कंस्ट्रक्टर को ओवरशैडो क्यों नहीं करता है?
  2. क्या एक ही प्रकार और वैकल्पिक प्रकार दोनों के प्रतिलिपि निर्माण की अनुमति देने के लिए कोई बेहतर समाधान है? अभी के रूप में मुझे प्रत्येक कॉपी/मूव कंस्ट्रक्टर और असाइनमेंट ऑपरेटर के लिए अनिवार्य रूप से कोड डुप्लिकेट करना होगा।
0
Rabster 27 जुलाई 2020, 07:08

1 उत्तर

सबसे बढ़िया उत्तर

https://en.cppreference.com/w/cpp/language/copy_constructor

क्लास टी का कॉपी कंस्ट्रक्टर एक गैर-टेम्पलेट कंस्ट्रक्टर है जिसका पहला पैरामीटर टी एंड ‍, कॉन्स्ट टी एंड ‍, वोलेटाइल टी एंड ‍, या कॉन्स्ट वोलेटाइल टी एंड है है, और या तो कोई अन्य पैरामीटर नहीं हैं, या बाकी सभी पैरामीटर में डिफ़ॉल्ट मान हैं।

इसलिए आप उस तरह से कॉपी सीटीओआर के लिए नए मापदंडों को परिभाषित नहीं कर सकते।

अब, यदि आप Bar<false>(const Bar<true>&) या Bar<false>(const Bar<true>&) का उपयोग करते हैं, तो कंपाइलर साधारण cpy ctor का उपयोग करेगा जो कि क्लास को इंस्टेंट करने पर उत्पन्न हुआ है और आपके संबंधित टेम्प्लेटेड ctor को इंस्टेंट नहीं करेगा।

और अगर यह सच है, तो कॉपी सीटीआर को परिभाषित करने के लिए कंपाइलर के लिए काम छोड़ दें, लेकिन unique_ptr को shared_ptr में बदल दें (क्योंकि unique_ptr के साथ एक सदस्य के रूप में वर्ग कॉपी करने योग्य नहीं है), या दो ctors को परिभाषित करें जैसा कि आपके पास दूसरे कोड में है।

निम्नलिखित कोड के लिए, मैंने shared_ptr का उपयोग किया है और कोई त्रुटि नहीं हुई है

लेकिन ध्यान दें कि टेम्प्लेटेड cpy ctor Bar<false/true>(const Bar<false/true>&) के लिए निष्पादित नहीं होता है, जबकि यह Bar<true/false>(const Bar<false/false>&) के लिए निष्पादित होता है

#include <memory>
#include <iostream>

template<bool binary>
class Bar {
private:
    Bar& operator=(const Bar&) = delete ;
    friend class Bar<!binary>;
    std::shared_ptr<int> data;
public:

    template<bool value>
    Bar(const Bar<value>& bar) : data(std::make_shared<int>(*bar.data)) {
        std::cout << __PRETTY_FUNCTION__ <<"\n";

    }
    Bar(int example) : data(std::make_shared<int>(example)) {

    }

    //other methods that differ depending on binary value...
};

int main() {
    Bar<false> b1{ 1 };
    Bar<false> b2{ b1 };
    Bar<true> b3 {b1};
    Bar<true> b4 {b3};
    Bar<false> b5 {b4};

}

रहना

1
asmmo 27 जुलाई 2020, 08:34