2015-06-03 6 views
7

मैं एक तर्क के आधार पर कन्स्ट्रक्टर में शुरू किए गए यूनियन सदस्य को चुनना चाहता हूं।सी ++ 14 कंस्ट्रैक्स संघ कन्स्ट्रक्टर में सशर्त प्रारंभिक

struct A { 
    union { 
     int i; 
     float f; 
    }; 
    A(double d, bool isint) { 
     if (isint) new(&i) int(d); 
     else new(&f) float(d); 
    } 
}; 

जब मैं int और float उपयोग कर रहा हूँ, लक्ष्य अन्य अधिक जटिल प्रकार के साथ काम करने के लिए (लेकिन अभी भी एक सी ++ 14 संघ में स्वीकार्य) है, इसलिए उपयोग: निम्नलिखित एक उदाहरण है कि काम करता है नियुक्ति के नए (और एक असाइनमेंट नहीं)।

समस्या यह है कि यह कन्स्ट्रक्टर constexpr नहीं हो सकता है क्योंकि constexpr विधियों में प्लेसमेंट-नई की अनुमति नहीं है। क्या इसके आसपास कोई रास्ता है (औपचारिक प्रकार प्रणाली के isint तर्क भाग बनाने के अलावा)? कुछ प्रकार की सशर्त इनटाइलाइज़र सूची काम करेगी, लेकिन मुझे ऐसा करने के तरीके से अनजान है।

+1

आईआईआरसी, निरंतर अभिव्यक्तियों के भीतर पनिंग को प्रतिबंधित (सामान्य रूप से) प्रतिबंधित किया जाता है। उदाहरण के लिए, आप सभी सदस्यों को अलग-अलग स्टोर कर सकते हैं ('संघ' के बजाय 'संरचना') और सदस्यों में से केवल एक को लागू करने के लिए encapsulation का उपयोग सक्रिय है। – dyp

+0

मुझे लगता है कि यह इस बात पर निर्भर करता है कि आप किस प्रकार के प्रकार पर विचार कर रहे हैं। मैं निश्चित रूप से एक कन्स्ट्रक्टर घोषित कर सकता हूं जो 'i' शुरू करता है और एक अलग 'जो' f' प्रारंभ करता है। यूनियन का केवल एक सदस्य किसी भी समय "सक्रिय" हो सकता है, लेकिन मैं इसे हटाने का प्रयास नहीं कर रहा हूं। मैं संकलक को बताकर खुश हूं कि सदस्य सक्रिय है। – cshelton

+3

आप सही हैं। प्लेसमेंट-न्यू का इस तरह का उपयोग वास्तव में टाइप सिस्टम को बाधित नहीं करता है। - बाहरी कार्य में ऐसा करना संभव है, उदा। 'constexpr एक make_A (डबल डी, बूल आइसिंट) {if (isint) वापसी ए (डी, true_type {}); अन्य ए (डी, false_type {}) वापस; } '। यदि आप इसके बजाय गैर-अज्ञात यूनियनों का उपयोग करते हैं, तो इस तरह के फ़ंक्शन को कन्स्ट्रक्टर के भीतर से कॉल करना संभव होना चाहिए।कुछ 'स्ट्रक्चर ए {यूनियन स्टोरेज {int i; फ्लोट एफ; भंडारण (डबल डी, true_type); भंडारण (डबल डी, false_type); } एम; ए (डबल डी, बूल आइसिंट): एम (मेक_स्टोरेज (डी, आईसेंट)) {}}; ' – dyp

उत्तर

6

एक चाल है। कुंजी पीस हैं:

  1. एक प्रति चूक या एक संघ प्रतियां के लिए निर्माता के लिए कदम वस्तु प्रतिनिधित्व (और इस प्रकार प्रतियां सक्रिय सदस्य), और निरंतर अभिव्यक्ति मूल्यांकन में अनुमति दी है।
  2. प्रारंभिकरण पूर्ण होने के बाद आप निरंतर अभिव्यक्ति मूल्यांकन में सक्रिय संघ सदस्य को नहीं बदल सकते हैं, लेकिन आप पसंद में देरी के लिए किसी अन्य निर्माता को प्रतिनिधि दे सकते हैं।
  3. यदि आप कॉपी करने या कन्स्ट्रक्टर को स्थानांतरित करने के लिए प्रतिनिधि हैं, तो आप किसी अन्य ऑब्जेक्ट में पास कर सकते हैं जो पहले से ही सही स्थिति में प्रारंभ हो चुका है और इसके सक्रिय सदस्य की प्रतिलिपि बना सकता है।

एक साथ इस लाना, हम पाते हैं:

template<typename T> struct tag {}; 
struct A { 
    union { 
    int i; 
    float f; 
    }; 
    constexpr A(tag<int>, double d) : i(d) {} 
    constexpr A(tag<float>, double d) : f(d) {} 
    constexpr A(double d, bool isint) : A(isint ? A(tag<int>(), d) : A(tag<float>(), d)) {} 
}; 

constexpr A a(1.0, true); // ok, initializes 'i' 
constexpr A b(5, false); // ok, initializes 'f' 

यह हाल बजना, जीसीसी, और ईडीजी द्वारा स्वीकार कर लिया है, और सी ++ केवल 11 constexpr की आवश्यकता है।

चेतावनी: जीसीसी 5.1.0 एक बग जहां यह ऊपर कोड miscompiled था (a और 0 करने के लिए b आरंभ); यह बग जीसीसी के पहले या बाद के संस्करणों में मौजूद नहीं है।

+0

क्या यह काम करता है यदि संघ के सदस्य तुच्छ नहीं हैं? मुझे नहीं लगता कि यह करता है। उदाहरण के लिए, मुझे ऐसा कक्षा में ऐसा करने में सक्षम होना चाहिए जिसमें प्रतिलिपि बनाने वाला न हो। फिर भी, मुझे नहीं लगता कि यह संभव है। – cshelton

+0

@cshelton हां, यह विधि बुलेटप्रूफ है। सदस्य प्रारंभकर्ता 'i (डी) 'सदस्य को" जगह में बना रहा है। " – Potatoswatter

+1

'ए' चाल का प्रेषण कन्स्ट्रक्टर 'ए' अस्थायी से 'ए' उदाहरण बनाता है; इस तकनीक के लिए उस चाल (या प्रतिलिपि) निर्माण को वैध होने की आवश्यकता होती है, जिसके बदले में वर्ग के सभी यूनियन सदस्यों (सरणी) वर्ग प्रकार को छोटे कदम (या प्रतिलिपि) रचनाकारों की आवश्यकता होती है। मुझे उस प्रतिबंध के आसपास एक रास्ता नहीं पता है। –

1

छोटी रचनात्मक वस्तुओं के लिए, new की कोई आवश्यकता नहीं है। आप ऑब्जेक्ट आजीवन शुरू कर सकते हैं, और केवल असाइनमेंट ऑपरेटर द्वारा सक्रिय union सदस्य का चयन करें।

struct A { 
    union { 
     int i; 
     float f; 
    }; 
    A(double d, bool isint) { 
     if (isint) i = d; 
     else f = d; 
    } 
}; 

अगर वहाँ वास्तव में एक निर्माता कहीं सदस्य के अंदर है, तो यह आवश्यक रिचर्ड के जवाब का उपयोग करने के लिए है।

+0

मेरी पढ़ाई के लिए, सवाल 'ए' के लिए' constexpr' कन्स्ट्रक्टर के लिए पूछ रहा था। आप कन्स्ट्रक्टर 'कॉन्टेक्सप्र' को यहां नहीं बना सकते क्योंकि निरंतर अभिव्यक्ति मूल्यांकन के दौरान यूनियन के सक्रिय सदस्य को बदलने की अनुमति नहीं है। –

+0

@ रिचर्डस्मिथ हाँ, आप सही हैं। क्लेंग और जीसीसी दोनों में कुछ मोटे किनारों दिखाई देते हैं और कुछ हद तक इस नियम को आराम देते हैं। जीसीसी सक्रिय सदस्य को बदलने की अनुमति देता है। (यदि 'constexpr' जोड़ा गया है तो दोनों इस उदाहरण को अस्वीकार कर दें।) – Potatoswatter

+0

@ रिचर्डस्मिथ कभी भी ध्यान न दें, क्लैंग अनुरूप है :)। – Potatoswatter

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