18

मेरा मानना ​​है कि अभिव्यक्ति T() एक रैल्यू (मानक द्वारा) बनाती है। हालांकि, निम्नलिखित कोड को संकलित करता है (कम से कम gcc4.0 पर):टी() = टी() क्यों अनुमति है?

class T {}; 

int main() 
{ 
    T() = T(); 
} 

मैं जानता हूँ कि तकनीकी रूप से यह संभव है क्योंकि सदस्य कार्यों temporaries पर लागू किया जा सकता है और इसके बाद के संस्करण बस ऑपरेटर लागू है = rvalue अस्थायी बनाया पर पहले T() से।

लेकिन अवधारणा यह एक रावल्यू के लिए एक नया मूल्य असाइन करने जैसा है। क्या इसका कोई अच्छा कारण है कि इसकी अनुमति क्यों है?

संपादित करें: कारण मुझे यह अजीब लगता है कि यह अभी तक उपयोगकर्ता द्वारा परिभाषित प्रकारों पर अंतर्निहित प्रकारों पर सख्ती से प्रतिबंधित है। उदाहरण के लिए, int(2) = int(3) संकलित नहीं होगा क्योंकि यह "असाइनमेंट में अमान्य अंतराल" है।

तो मुझे लगता है कि वास्तविक सवाल यह है कि, क्या यह किसी कारण के लिए भाषा में बनाया गया कुछ असंगत व्यवहार था? या क्या यह कुछ ऐतिहासिक कारणों से है? (उदाहरण के लिए यह अवधारणात्मक रूप से अधिक ध्वनि होगा, केवल रद्दी अभिव्यक्तियों पर केवल कॉन्स्ट सदस्य कार्यों को लागू करने की अनुमति देने के लिए, लेकिन ऐसा नहीं किया जा सकता क्योंकि यह कुछ मौजूदा कोड तोड़ सकता है।)

उत्तर

3

यही कारण है कि कई है मानक पुस्तकालय में कक्षाओं को लागू किया जा सकता है। उदाहरण std::bitset<>::operator[]

// bit reference: 
class reference { 
    friend class bitset; 
    reference(); 
public: 
    ˜reference(); 
    reference& operator=(bool x);   // for b[i] = x; 
    reference& operator=(const reference&); // for b[i] = b[j]; 
    bool operator˜() const; // flips the bit 
    operator bool() const; // for x = b[i]; 
    reference& flip();  // for b[i].flip(); 
}; 

reference operator[](size_t pos); // for b[i]; 

के लिए विचार करें आप bits[i] = true करते हैं कि वास्तव में आप वर्ग प्रकार का एक rvalue करने के लिए कुछ मूल्य निर्दिष्ट। operator[] द्वारा लौटाई गई प्रॉक्सी उन बिट्स तक पहुंच सकती है जो अंतरिक्ष कुशलतापूर्वक पूर्णांक में पैक की जाती हैं।

+0

यह फ्रेडओवरफ्लो के उत्तर के साथ मेरे प्रश्न का पूरी तरह उत्तर देता है। धन्यवाद! – Rimo

13

यह ऑपरेटर ओवरलोडिंग के कारण पूरी तरह से अनुमति है, और संभावना है कि आप कुछ अधिक फैंसी करने के लिए operator = ओवरलोड कर सकते हैं, जैसे कि कंसोल पर प्रिंट करें, या म्यूटेक्स को लॉक करें, या वास्तव में कुछ भी।

+16

और न केवल ऑपरेटर = बल्कि निर्माता भी। सी ++ में बहुत सारे अजीब निर्माण हैं जहां संकलक सिर्फ चिल्लाता है और आशा करता है कि आप जानते हैं कि आप क्या कर रहे हैं। :-) –

7

हां, आप एक रावल्यू के लिए एक नया मूल्य असाइन कर रहे हैं। अधिक सटीक, आप एक रैल्यू पर operator = सदस्य फ़ंक्शन को कॉल कर रहे हैं। चूंकि आप अंतर्निहित असाइनमेंट ऑपरेटर का उपयोग नहीं कर रहे हैं, आपको ऐसा क्यों लगता है कि यह एक समस्या होनी चाहिए? operator = कक्षा का एक सदस्य कार्य है, जो कि ज्यादातर मामलों में वर्ग के किसी भी अन्य सदस्य कार्य के समान है, जिसमें तथ्य यह है कि इसे राजस्व पर बुलाया जा सकता है।

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

(T() = T()).some_member_function(); 

तुम भी विस्तार कर सकते हैं *this के माध्यम से 'नई' (हाल में सौंपा) अस्थायी वस्तु के मूल्य देखेंगे const T& r = T() = T(); पर एक कॉन्स्ट-संदर्भ संलग्न करके अस्थायी जीवनकाल और r के माध्यम से देखा गया मान ऑब्जेक्ट का "नया" मान होगा। जैसा कि जोहान्स ने अपनी टिप्पणी में सही ढंग से ध्यान दिया, यह इसे अस्थायी रूप से संलग्न नहीं करेगा।

+0

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

+0

बस स्पष्ट करने के लिए, व्यक्तिगत रूप से अगर यह केवल मूल सदस्य कार्यों को रावल्यू अभिव्यक्तियों पर लागू करने की अनुमति है तो इसे बहुत कम आश्चर्यजनक लगता है। – Rimo

+3

@ रिमियो: यह 'परमाणु (std :: cout) << 1 << "निर्बाध आउटपुट" जैसे उचित संरचनाओं को हराता है << std :: endl; ' – MSalters

4

एक पीओवी से, यह असंगत है, लेकिन आप की ओर मुख कर रहे हैं यह कैसे संगत है: 1) ints और अन्य में निर्मित प्रकार अभी भी व्यवहार करते हैं जैसा कि वे सी में करते हैं, 2) ऑपरेटर = वर्ग प्रकार पर बर्ताव करता है क्योंकि किसी अन्य विधि को अभी तक एक और विशेष मामले की आवश्यकता के बिना किया जाता है।

सी संगतता सी ++ की शुरुआत के बाद से अत्यधिक मूल्यवान है, और सी ++ तर्कसंगत रूप से इसके बिना आज यहां नहीं होगा। तो वह हिस्सा आम तौर पर एक अच्छी बात है।

दूसरा बिंदु कम किया गया है। विशेष आवरण ऑपरेटर नहीं = बकवास कोड को "काम" करने की अनुमति देता है, लेकिन हम पहली जगह बकवास कोड की परवाह क्यों करते हैं? कचरा अंदर कचरा बाहर।वर्तमान नियमों ने इसे एक परिभाषित अर्थ (यूबी यहां खराब होगा) नगण्य लागत के साथ, जहां तक ​​मैंने कभी देखा है।

मेरे ड्रूटर को देखते हुए, चीजों को और भी सरल बनाया जाएगा, इसलिए int() = int() की अनुमति होगी। C++ 0x, rvalue-संदर्भ, prvalues ​​साथ उस दिशा में सिर शुरू होता है आदि

+0

"_C++ 0x उस दिशा में रावल-संदर्भ, मूल्य, इत्यादि के साथ शुरू होता है_" गले लगाओ? – curiousguy

5

आप ऑपरेटर सीमित कर सकते हैं = सी में lvalues ​​पर केवल काम करने के लिए ++ 0x:

class T 
{ 
public: 
    T& operator=(const T&) & = default; 
}; 
संबंधित मुद्दे