C ++ 17 अद्यतन
C ++ 17 में, A_factory_func()
एक अस्थायी वस्तु (C ++ <= 14) बनाने से बदले जाने का अर्थ यह है कि C ++ 17 में जिस भी वस्तु की अभिव्यक्ति शुरू की गई है (शिथिल रूप से बोलना), उसको प्रारंभ करना। ये ऑब्जेक्ट्स ("परिणाम ऑब्जेक्ट्स") एक घोषणा (जैसे a1
) द्वारा बनाए गए वेरिएबल्स हैं , जब आरंभीकरण समाप्त होने पर कृत्रिम ऑब्जेक्ट बनाए जाते हैं, या संदर्भ बंधन के लिए किसी ऑब्जेक्ट की आवश्यकता होती है (जैसे, A_factory_func();
अंतिम मामले में) । एक वस्तु कृत्रिम रूप से बनाई जाती है, जिसे "अस्थायी भौतिककरण" कहा जाता है, क्योंकि A_factory_func()
इसमें एक चर या संदर्भ नहीं होता है जो अन्यथा मौजूद होने के लिए एक वस्तु की आवश्यकता होती है)।
हमारे मामले में उदाहरण के रूप में, a1
और a2
विशेष नियमों के मामले में कहा गया है कि इस तरह की घोषणाओं में, एक ही प्रकार के एक प्रचलित इक्वलाइज़र का परिणाम ऑब्जेक्ट a1
चर है a1
, और इसलिए A_factory_func()
सीधे ऑब्जेक्ट को इनिशियलाइज़ करता है a1
। किसी भी मध्यस्थ कार्यात्मक-शैली के कलाकारों पर कोई प्रभाव नहीं पड़ेगा, क्योंकि A_factory_func(another-prvalue)
सिर्फ "से गुजरता है" बाहरी वस्तु के परिणाम वस्तु के भीतर के परिणाम का परिणाम भी होता है।
A a1 = A_factory_func();
A a2(A_factory_func());
किस प्रकार के A_factory_func()
रिटर्न पर निर्भर करता है। मुझे लगता है कि यह एक रिटर्न देता है A
- फिर यह वही कर रहा है - सिवाय इसके कि जब कॉपी कंस्ट्रक्टर स्पष्ट हो, तो पहले वाला विफल हो जाएगा। 8.6 / 14 पढ़ें
double b1 = 0.5;
double b2(0.5);
यह वही कर रहा है क्योंकि यह बिल्ट-इन टाइप है (इसका मतलब यहां क्लास टाइप नहीं है)। 8.6 / 14 पढ़ें ।
A c1;
A c2 = A();
A c3(A());
यह वही नहीं कर रहा है। यदि A
कोई गैर-POD है, तो पहला डिफ़ॉल्ट-आरंभ करता है, और POD के लिए कोई प्रारंभ नहीं करता है (पढ़ें 8.6 / 9 )। दूसरी प्रति इनिशियलाइज़ करती है: वैल्यू इनिशियलाइज़ करती है एक अस्थायी और फिर उस वैल्यू को कॉपी करती है c2
(पढ़ें 5.2.3 / 2 और 8.6 / 14 )। इस पाठ्यक्रम के लिए एक गैर-स्पष्ट प्रतिलिपि निर्माता की आवश्यकता होगी (पढ़ें 8.6 / 14 और 12.3.1 / 3 और 13.3.1.3/1 )। तीसरा एक फ़ंक्शन के लिए एक फ़ंक्शन घोषणापत्र बनाता है जो एक c3
रिटर्न देता है A
और जो एक फ़ंक्शन पॉइंटर को एक रिटर्न A
( एक 8.2 ) पढ़ता है ।
इनिशियलाइज़ेशन में डायरेक्ट और कॉपी इनिशियलाइज़ेशन
जबकि वे समान दिखते हैं और ऐसा ही करने वाले होते हैं, ये दोनों रूप कुछ मामलों में उल्लेखनीय रूप से भिन्न होते हैं। आरंभीकरण के दो रूप प्रत्यक्ष और प्रतिलिपि आरंभीकरण हैं:
T t(x);
T t = x;
व्यवहार है हम उनमें से प्रत्येक के लिए विशेषता कर सकते हैं:
- प्रत्यक्ष आरंभीकरण एक अतिभारित कार्य के लिए एक फ़ंक्शन कॉल की तरह व्यवहार करता है: कार्य, इस मामले में,
T
(सहित explicit
) के निर्माता हैं, और तर्क है x
। ओवरलोड रिज़ॉल्यूशन में सबसे अच्छा मिलान करने वाला कंस्ट्रक्टर मिलेगा, और जब आवश्यक होगा कोई आवश्यक रूपांतरण करेगा।
- प्रतिलिपि आरंभीकरण एक अंतर्निहित रूपांतरण अनुक्रम का निर्माण करता है: यह
x
एक प्रकार की वस्तु में बदलने की कोशिश करता है T
। (यह तब उस ऑब्जेक्ट को इन-इनिशियलाइज्ड ऑब्जेक्ट में कॉपी कर सकता है, इसलिए कॉपी कंस्ट्रक्टर की भी आवश्यकता है - लेकिन यह नीचे दिए गए महत्वपूर्ण नहीं है)
जैसा कि आप देखते हैं, कॉपी इनिशियलाइज़ेशन किसी तरह से संभव अंतर्निहित रूपांतरण के संबंध में प्रत्यक्ष आरंभीकरण का एक हिस्सा है: जबकि प्रत्यक्ष इनिशियलाइज़ेशन में कॉल करने के लिए सभी कंस्ट्रक्टर उपलब्ध हैं, और इसके अलावा किसी भी अंतर्निहित रूपांतरण को तर्क प्रकारों से मेल खाने की आवश्यकता हो सकती है, कॉपी सत्यापन बस एक अंतर्निहित रूपांतरण अनुक्रम सेट कर सकते हैं।
मैंने कड़ी मेहनत की और निर्माणकर्ताओं के माध्यम से "स्पष्ट" का उपयोग किए बिना, उन रूपों में से प्रत्येक के लिए अलग-अलग पाठ को आउटपुट करने के लिए निम्न कोड प्राप्तexplicit
किया।
#include <iostream>
struct B;
struct A {
operator B();
};
struct B {
B() { }
B(A const&) { std::cout << "<direct> "; }
};
A::operator B() { std::cout << "<copy> "; return B(); }
int main() {
A a;
B b1(a); // 1)
B b2 = a; // 2)
}
// output: <direct> <copy>
यह कैसे काम करता है, और इसका परिणाम क्यों होता है?
प्रत्यक्ष आरंभीकरण
यह पहले रूपांतरण के बारे में कुछ नहीं जानता है। यह सिर्फ एक निर्माता को कॉल करने का प्रयास करेगा। इस मामले में, निम्नलिखित कंस्ट्रक्टर उपलब्ध है और एक सटीक मिलान है :
B(A const&)
कोई रूपांतरण नहीं है, बहुत कम उपयोगकर्ता परिभाषित रूपांतरण, उस निर्माता को कॉल करने की आवश्यकता है (ध्यान दें कि कोई भी कॉन्स्टेबल योग्यता रूपांतरण यहां भी नहीं होता है)। और इसलिए प्रत्यक्ष प्रारंभ इसे कहेंगे।
आरंभीकरण की प्रतिलिपि बनाएँ
जैसा कि ऊपर कहा गया है, कॉपी इनिशियलाइज़ेशन एक रूपांतरण अनुक्रम का निर्माण करेगा जब a
उससे टाइप B
या व्युत्पन्न नहीं हुआ है (जो स्पष्ट रूप से यहाँ मामला है)। तो यह रूपांतरण करने के तरीकों की तलाश करेगा, और निम्नलिखित उम्मीदवारों को ढूंढेगा
B(A const&)
operator B(A&);
ध्यान दें कि मैंने रूपांतरण फ़ंक्शन को कैसे फिर से लिखा है: पैरामीटर प्रकार this
पॉइंटर के प्रकार को दर्शाता है , जो गैर-कॉन्स्टेबल सदस्य फ़ंक्शन में गैर-कॉन्स्टेंस के लिए है। अब, हम इन उम्मीदवारों x
को तर्क के साथ बुलाते हैं । विजेता रूपांतरण फ़ंक्शन है: क्योंकि यदि हमारे पास दो उम्मीदवार कार्य हैं जो दोनों एक ही प्रकार के संदर्भ को स्वीकार करते हैं, तो कम कॉन्स्टेंस संस्करण जीतता है (इस तरह से, गैर-सदस्य सदस्य फ़ंक्शन को गैर के लिए प्राथमिकता देने वाला तंत्र भी गैर के लिए कहता है -संबंधी वस्तुएं)।
ध्यान दें कि यदि हम रूपांतरण फ़ंक्शन को एक सदस्य सदस्य फ़ंक्शन के रूप में बदलते हैं, तो रूपांतरण अस्पष्ट है (क्योंकि दोनों में एक पैरामीटर प्रकार है A const&
): कॉम्यू कंपाइलर इसे ठीक से अस्वीकार करता है, लेकिन जीसीसी इसे गैर-पांडित्यपूर्ण मोड में स्वीकार करता है। -pedantic
यह उचित अस्पष्टता चेतावनी भी उत्पादन करने के लिए स्विचन हालांकि।
मुझे उम्मीद है कि यह कुछ हद तक यह स्पष्ट करने में मदद करता है कि ये दो रूप कैसे भिन्न हैं!
A c1; A c2 = c1; A c3(c1);
।