2015-02-26 8 views
5

पर रावल्यू संदर्भ के पारित होने की अनुमति नहीं है हमारे पास निम्न सुविधा फ़ंक्शन है जो मानचित्र से कोई मान प्राप्त करता है या यदि नहीं मिला तो फ़ॉलबैक डिफ़ॉल्ट मान देता है।किसी फ़ंक्शन

template <class Collection> const typename Collection::value_type::second_type& 
    FindWithDefault(const Collection& collection, 
        const typename Collection::value_type::first_type& key, 
        const typename Collection::value_type::second_type& value) { 
     typename Collection::const_iterator it = collection.find(key); 
     if (it == collection.end()) { 
     return value; 
     } 
     return it->second; 
    } 

इस समारोह के साथ समस्या यह तीसरा तर्क जो एक बग होगा के रूप में एक अस्थायी वस्तु गुजर अनुमति देता है। उदाहरण के लिए:

const string& foo = FindWithDefault(my_map, ""); 

यह std :: is_rvalue_reference और स्थिर ज़ोर का उपयोग करके किसी तरह से तीसरा तर्क को rvalue संदर्भ गुजर अस्वीकृत करने के लिए संभव है?

+0

यह वास्तव में '' 'पास करने के लिए सहज महसूस करता है। 'FindWithDefault' को संदर्भ में बाध्य होने से रोकने के लिए एक तरीका खोजना बेहतर होगा, सिवाय इसके कि मुझे नहीं लगता कि एक है। वैसे भी, इस उदाहरण में बस 'foo' मान बनाना बेहतर होगा। –

+1

इस प्रश्न के साथ दूसरी समस्या यह है कि आप समस्या को बताए जाने के बजाय समाधान के बारे में सोचते हैं। ऐसा करने में, आपने रावल संदर्भों पर ध्यान केंद्रित किया है लेकिन यह एकमात्र समस्या नहीं है; एक लालसा संदर्भ-से-'const'-अस्थायी आपको उतना ही कठिन बना देगा। शायद मूल्य से डिफ़ॉल्ट 'मान' ले लो। –

+0

आप संदर्भ द्वारा लौटने की बजाय मूल्य से वापस आ सकते हैं। यह एक खोज के साथ डिफ़ॉल्ट के लिए काफी प्राकृतिक लगता है। – galinette

उत्तर

6

इस अतिरिक्त अधिभार जोड़ना (untested) काम करना चाहिए:

template <class Collection> 
const typename Collection::value_type::second_type& 
FindWithDefault(const Collection& collection, 
       const typename Collection::value_type::first_type& key, 
       const typename Collection::value_type::second_type&& value) = delete; 

अधिभार संकल्प rvalue संदर्भ के लिए यह अधिभार चुनेंगे और = delete यह एक संकलन समय त्रुटि करता है। वैकल्पिक रूप से, अगर आप एक कस्टम संदेश निर्दिष्ट करना चाहते हैं, तो आप

template <class Collection> 
const typename Collection::value_type::second_type& 
FindWithDefault(const Collection& collection, 
       const typename Collection::value_type::first_type& key, 
       const typename Collection::value_type::second_type&& value) { 
    static_assert(
     !std::is_same<Collection, Collection>::value, // always false 
     "No rvalue references allowed!"); 
} 

std::is_same के लिए वहाँ है टेम्पलेट पैरामीटर पर static_assert निर्भर बनाने के लिए जा सकते हैं, अन्यथा यह एक संकलन त्रुटि उत्पन्न होगी तब भी जब अधिभार नहीं बुलाया जाता है ।

संपादित करें:

rval.cpp(8) : error C2280: 'void foo(const char &&)' : attempting to reference a deleted function 
     rval.cpp(2): See declaration of 'foo' 

पहली कॉल, तथापि, ठीक काम करता है और यदि:

void foo(char const&) { }; 
void foo(char const&&) = delete; 

int main() 
{ 
    char c = 'c'; 
    foo(c); // OK 
    foo('x'); // Compiler error 
} 

MSVC दूसरी कॉल के लिए त्रुटि निम्न यहाँ foo के लिए देता है: यहाँ एक न्यूनतम पूरा उदाहरण है प्रोग्राम को संकलित करते समय आप दूसरी बार टिप्पणी करते हैं।

+1

अस्थायी वस्तु में इस बारे में एक बड़ी लाल चेतावनी लिखते हैं! = Rvalue संदर्भ। आपके पास एक अस्थायी वस्तु हो सकती है। – user1095108

+0

@ user1095108: सच है, लेकिन फिर अस्थायी कम से कम संदर्भ के रूप में जीवित रहेगा, और यह गलती से पारित करना इतना आसान नहीं है (मुझे लगता है कि आपका मतलब है 'char const & ct =' t '; foo (ct) ; ')। – Oberon

+0

धन्यवाद! मुझे नहीं पता था कि आप वैश्विक कार्यों के लिए 'हटाएं' संशोधक का उपयोग कर सकते हैं। – Roman

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