2016-05-04 10 views
10

मैं vector बनाने की कोशिश कर रहा हूं जो string और int रख सकता है।दो प्रकार के संघ का उपयोग कैसे करें

मैं नीचे दिए गए कोड की कोशिश की है, लेकिन मैं संकलन त्रुटि

error: use of deleted function 'my_union::~my_union()'

क्या मैं गलत कर रहा हूँ मिल सकता है?

#include <iostream> 
#include <vector> 

using namespace std; 

union my_union 
{ 
    string str; 
    int a; 
}; 

int main() 
{ 
    vector<my_union> v; 
    my_union u;   // error: use of deleted function 'my_union::~my_union()' 
    u.str = "foo"; 
    v.push_back(u); 
    return 0; 
} 
+0

फिर से खोला गया: सी ++ 11 ने संघ में क्या अनुमति दी है, और 'std :: string', दूसरों के बीच, अब विस्तारित है। –

+1

@PeteBecker मुझे वह मिलता है लेकिन क्या यह [इस] में शामिल नहीं है (http://stackoverflow.com/a/3521998/4342498) क्यू से उत्तर? – NathanOliver

+2

आप बाद में वेक्टर से पढ़ने के लिए संघ के किस सदस्य को 'जानना' की योजना बना रहे हैं? –

उत्तर

14

here

If a union contains a non-static data member with a non-trivial special member function (default constructor, copy/move constructor, copy/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer.

से आप स्पष्ट रूप से अपने संघ स्वचालित रूप से string के लिए नष्ट कर दिया बदलने के लिए बस के लिए एक नाशक परिभाषित करना होगा।

यह भी ध्यान दें कि यह केवल सी ++ 11 में मान्य है। पिछले संस्करणों में आपके पास यूनियन के अंदर गैर-तुच्छ विशेष सदस्य कार्यों के साथ एक प्रकार नहीं हो सकता है।

व्यावहारिक दृष्टिकोण से, यह अभी भी एक अच्छा विचार नहीं हो सकता है।

+4

"हो सकता है ... एक अच्छा विचार न हो" - वास्तव में। जब आपके पास गैर-तुच्छ कन्स्ट्रक्टर या विनाशकों के प्रकार होते हैं तो आपको संघ में एक अलग प्रकार के ऑब्जेक्ट को स्टोर करने के लिए प्लेसमेंट नए और स्पष्ट विनाशक कॉल का उपयोग करना होगा। –

+1

@CodesInChaos इस प्रश्न पर एक टिप्पणी [boost :: variant] (http://www.boost.org/doc/libs/1_60_0/doc/html/variant.html) को इंगित करती है। मैंने इसे स्वयं नहीं उपयोग किया है, लेकिन वेबपेज पर विवरण से यह एक उदाहरण के रूप में प्रश्न में स्थिति को सही तरीके से भी प्रदान करता है। – Rotem

1

सी ++ 11 यह एक संघ में std::string उपयोग करने के लिए के रूप में उद्धृत here की अनुमति नहीं थी पहले:

Unions cannot contain a non-static data member with a non-trivial special member function (copy constructor, copy-assignment operator, or destructor).

और चूंकि सी ++ 11 आप एक संघ के रूप में पहले से ही @Rotem द्वारा उत्तर में std::string उपयोग कर सकते हैं, तो आप जब आप एक वर्ग है कि मूल रूप से सादे पुराने डेटा नहीं है, सी ++ 11 में यह आप की सुविधा देता है के साथ एक संघ बनाने के एक नाशक स्पष्ट स्ट्रिंग के लिए नाशक explicitly

str.~basic_string<char>(); 
2

परिभाषित या कॉल करने के लिए की जरूरत है। लेकिन यह विनाशक जैसे विशेष सदस्य कार्यों में से अधिकांश को स्पष्ट रूप से हटा देता है।

union my_union 
{ 
    string str; 
    int a; 
}; 

व्यावहारिक समस्या यह है कि विनाश सी के बिंदु पर ++ जो संघ के ऊपर भागों के मान्य हैं पता नहीं है।

आप टैग किए गए यूनियन का उपयोग करके और सक्रिय ट्रैक ट्रैक रखने और मैन्युअल रूप से उस मामले में विनाश करने के द्वारा इस पर काम कर सकते हैं।

struct tagged_union { 
    enum active {nothing, string, integer} which_active; 
    template<active...As> 
    using actives = std::integral_sequence<active, As...> 
    using my_actives = actives<nothing, string, integer>; 

    struct nothingness {}; 

    union my_union 
    { 
    nothingness nothing; 
    std::string str; 
    int a; 
    ~my_union() {}; 
    } data; 
    using my_tuple = std::tuple<nothingness, std::string, int>; 

    template<active which> 
    using get_type = std::tuple_element_t<(std::size_t)which, my_tuple>; 

    template<class F> 
    void operate_on(F&& f) { 
    operate_on_internal(my_actives{}, std::forward<F>(f)); 
    } 
    template<class T, class F> 
    decltype(auto) operate_on_by_type(F&& f) { 
    return std::forward<F>(f)(reinterpret_cast<T*>(&data)); 
    } 
    // const versions go here 
private: 
    // a small magic switch: 
    template<active...As, class F>  
    void operate_on_internal(actives<As...>, F&& f) { 
    using ptr = void(*)(my_union*,std::decay_t<F>*); 
    const ptr table[]={ 
     [](my_union* self, std::decay_t<F>* pf){ 
     std::forward<F>(*pf)(*(get_type<As>*)self); 
     }..., 
     nullptr 
    }; 
    table[which](&data, std::address_of(f)); 
    } 
public: 
    template<class...Args> 
    tagged_union(Active w, Args&&...args) { 
    operate_on([&](auto& t){ 
     using T = std::decay_t<decltype(t)>(); 
     ::new((void*)std::addressof(t)) T(std::forward<Args>(args)...); 
     which = w; 
    }); 
    } 
    tagged_union():tagged_union(nothing){} 

    ~tagged_union() { 
    operate_on([](auto& t){ 
     using T = std::decay_t<decltype(t)>(); 
     t->~T(); 
     which=nothing; 
     ::new((void*)std::addressof(t)) nothingness{}; // "leaks" but we don't care 
    }); 
    } 
}; 

जो मूल रूप से कैसे boost::variant कुछ की तरह काम करता है, तो सी ++ 11 में लिखा की एक आदिम स्केच है:

तो हम जैसे कुछ मिल सकता है।

इसमें कुछ भारी मोजो शामिल हैं।

उपर्युक्त संकलित नहीं किया गया है, लेकिन डिज़ाइन ध्वनि है। कुछ नाममात्र सी ++ 14 कंपाइलर्स एक पूर्ण लैम्ब्डा के चारों ओर एक पैक का विस्तार करना पसंद नहीं करते हैं, हालांकि, और भी बॉयलरप्लेट की आवश्यकता होगी।

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