2013-06-10 9 views
10

मैं इस तरह एक टेम्पलेट:std :: वर्ग टेम्पलेट में निर्माता प्रारंभकर्ता सूची में कदम

template<typename T> 
struct foo { 
    T m_t; 
    foo(T t) : m_t(t) {} 
}; 

समस्या यह है कि मैं दोनों छोटे/नियमित प्रकारों का समर्थन करना चाहते हैं और विशाल प्रकार (मैट्रिक) की तरह है T के लिए। आप की सिफारिश करते हैं मैं इस

foo (T t) : m_t(std::move(t)) {} 

की तरह निर्माता प्रारंभकर्ता सूची लिख सकते हैं और अपेक्षा करते हैं कि प्रकार T हमेशा भी छोटे प्रकार के लिए कदम निर्माण का समर्थन है,? क्या बेहतर तरीके हैं?

उत्तर

11

और आवश्यकता है कि प्रकार टी हमेशा छोटे प्रकार के लिए भी निर्माण निर्माण का समर्थन करता है?

कोई भी प्रकार जो प्रतिलिपि बनाने योग्य है, भी रचनात्मक हो जाता है। उन मामलों में जाने से बस कॉपी कन्स्ट्रक्टर को कॉल किया जाता है। इस प्रकार, का उपयोग करने के लिए पर कोई कारण नहीं है।

एक वैकल्पिक बजाय संदर्भ का उपयोग करने के लिए है:

foo (T const& t) : m_t(t) {} 
foo (T&& t) : m_t(std::move(t)) {} 

यह केवल दो के बजाए एक निर्माण को शामिल का लाभ मिलता है।

+0

क्या आपका संदर्भ तरीका मेरे से बेहतर है? यदि टी निर्माण योग्य नहीं है तो यह (या होना चाहिए) निहित है कि टी छोटा/सामान्य (बड़ा नहीं) है, है ना? इस मामले में क्या आपको लगता है कि एक संदर्भ मुझे किसी भी मापनीय प्रदर्शन लाभ देता है? – 7cows

+0

@ 7cows यह एक मापनीय प्रदर्शन लाभ दे सकता है जब टी में एक महंगी प्रतिलिपि निर्माता और कोई चालक कन्स्ट्रक्टर नहीं है, जो सी ++ 03 पुस्तकालयों के साथ आम है। मैं आमतौर पर आमतौर पर अपना रास्ता पसंद करते हैं। – Pubby

7

हां, इस स्थिति का उपयोग करने से उस स्थिति में कोई नुकसान नहीं होता है। सभी कॉपी करने योग्य ऑब्जेक्ट्स स्वचालित रूप से चलने योग्य होते हैं, इसलिए इससे कोई फर्क नहीं पड़ता। वास्तव में, कुछ हमेशा संभव होने पर भी चर को स्थानांतरित करने की सलाह देते हैं।

एक विकल्प के रूप में, आप सही अग्रेषण का उपयोग करने, this answer में वर्णित के रूप में विचार कर सकते:

template <typename T2> 
foo(T2&& t) : m_t(std::forward<T2>(t)) {} 

आप जानते हैं कि T एक तेजी से कदम निर्माता को परिभाषित करता है, तो इससे कोई फर्क नहीं करना चाहिए। अन्यथा, अनावश्यक प्रतियों से बचने के लिए एक निर्माता foo(const T&) प्रदान करने की अनुशंसा की जाती है।

बिल्कुल सही अग्रेषण यह प्राप्त करने के लिए केवल एक तकनीक है। कन्स्ट्रक्टर foo(const T&) और foo(T&&) लिखने के लिए पब्बी का समाधान निश्चित रूप से भी ठीक है। परिणाम समान हैं, यह ज्यादातर शैली का मामला है।

आपने छोटे पूर्णांक प्रकारों के बारे में भी पूछा। सिद्धांत रूप में, संदर्भ द्वारा उन्हें पास करना उन्हें कॉपी करने से धीमा है, लेकिन संकलक इसे किसी प्रतिलिपि में अनुकूलित करने में सक्षम होना चाहिए, वैसे भी। मुझे नहीं लगता कि इससे कोई फर्क पड़ेगा।

तो, सबसे बुरी स्थिति के लिए बेहतर अनुकूलन करें जहां T विशाल हो सकता है और तेजी से चलने वाला कन्स्ट्रक्टर प्रदान नहीं करता है। संदर्भ द्वारा पास करना उस स्थिति के लिए सबसे अच्छा है और सामान्य रूप से खराब विकल्प नहीं होना चाहिए।

+2

सही अग्रेषण के साथ समस्या यह है कि यह * सबकुछ * स्वीकार करेगा जो 'टी' का कन्स्ट्रक्टर स्वीकार करता है। – Pubby

+0

@ पब्बी अच्छा बिंदु। संदर्भ के आधार पर यह सकारात्मक या नकारात्मक हो सकता है। यदि रूपांतरणों पर अधिक नियंत्रण की आवश्यकता है, तो 'foo' रचनाकार दोनों को अतिरिक्त रूप से' स्पष्ट 'घोषित किया जा सकता है। –

+0

@ पब्बी, जिसे 'enable_if' और 'is_same' चेक के साथ नियंत्रित किया जा सकता है। अनुमोदित, जब तक आप इसे लिखे गए हों, तो संभवतः आप दोनों रचनाकारों को स्पष्ट रूप से कार्यान्वित करने के समान लाइनों को देख रहे हैं ... –

0

मूल्य से गुजरने से केवल एक ही कन्स्ट्रक्टर (टेम्पलेट के बिना) का लाभ होता है, लेकिन उपर्युक्त विकल्पों की तुलना में एक अतिरिक्त चाल निर्माण की कीमत पर आता है।

हालांकि, पब्बी द्वारा दिए गए पास-बाय-वैल्यू और गैर-टेम्पलेट समाधान दोनों की एक और अभी तक अनियमित कमी है: यदि प्रतिलिपि को T(T&); के रूप में परिभाषित किया गया है तो स्थानांतरण कार्य नहीं करेगा (गैर-कॉन्स के संदर्भ को नोट करें)।रावल्यू-रेफरेंस लैल्लू-रेफरेंस-टू-कॉन्स से जुड़ सकते हैं, लेकिन लैल्यू-रेफरेंस-टू-कॉन्स्टेंट नहीं, इसलिए संकलक कॉपी कन्स्ट्रक्टर को कॉल नहीं कर सकता है।

इस समस्या को हल करने के लिए, आप बस पब्बी के समाधान में तीसरा अधिभार foo (T & t) : m_t(t) {} जोड़ सकते हैं।

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