2016-04-19 8 views
17
here के अनुसार

में अवांछित रूपांतरण, explicit:रोकें निर्माता

कि अंतर्निहित रूपांतरण की अनुमति देने या कॉपी प्रारंभ नहीं है (सी ++ 11 के बाद से) निर्माणकर्ता और रूपांतरण ऑपरेटरों निर्दिष्ट करता है।

इस प्रकार, क्या ये दो तकनीक समान हैं?

struct Z { 
     // ... 
     Z(long long);  // can initialize with a long long 
     Z(long) = delete; // but not anything smaller 
}; 

struct Z { 
     // ... 
     explicit Z(long long);  // can initialize ONLY with a long long 
}; 

उत्तर

17

वे समान नहीं हैं।

Z z = 1LL; 

गैर स्पष्ट संस्करण के साथ ऊपर काम करता है, लेकिन स्पष्ट संस्करण के साथ नहीं।

Z का कन्स्ट्रक्टर घोषित करना स्पष्ट रूप से किसी अन्य प्रकार से कन्स्ट्रक्टर तर्क के रूपांतरण को रोकता नहीं है। यह कन्स्ट्रक्टर को स्पष्ट रूप से कॉल किए बिना तर्क से रूपांतरण को Z पर रोकता है।

नीचे स्पष्ट कन्स्ट्रक्टर कॉल का एक उदाहरण है।

Z z = Z(1LL); 
+3

नोट, जो स्पष्ट कन्स्ट्रक्टर, और प्रतिलिपि/चालक कन्स्ट्रक्टर को भी कॉल करता है। 'जेड जेड (1 एलएल); 'केवल स्पष्ट कन्स्ट्रक्टर को कॉल करेगा। – immibis

24

नहीं, वे वही नहीं हैं। explicit उस प्रकार के निहित रूपांतरणों को अस्वीकार करता है यदि उस कन्स्ट्रक्टर का चयन किया गया है - तर्कों में अंतर्निहित रूपांतरण कोई फर्क नहीं पड़ता। delete किसी भी निर्माण को अस्वीकार करता है अगर उस कन्स्ट्रक्टर का चयन किया जाता है, और इसका उपयोग अंतर्निहित तर्क रूपांतरण को अस्वीकार करने के लिए किया जा सकता है।

उदाहरण के लिए

तो:

struct X { 
    explicit X(int) { } 
}; 

void foo(X) { } 

foo(4);  // error, because X's constructor is explicit 
foo(X{3}); // ok 
foo(X{'3'}); // ok, this conversion is fine 

delete से कि अलग है एक निर्माता ing:

struct Y { 
    Y(int) { } 
    Y(char) = delete; 
}; 

void bar(Y) { } 

bar(4);  // ok, implicit conversion to Y since this constructor isn't explicit 
bar('4'); // error, this constructor is deleted 
bar(Y{'4'}); // error, doesn't matter that we're explicit 

दो तकनीकों भी ओर्थोगोनल हैं। यदि आप चाहते हैं एक प्रकार परोक्ष-परिवर्तनीय और वास्तव में एक int से केवल constructible नहीं हो, तो आप दोनों कर सकते हैं:

struct W { 
    explicit W(int) { } 

    template <class T> 
    W(T) = delete; 
}; 

void quux(W); 

quux(4);  // error, constructor is explicit 
quux('4'); // error, constructor is deleted 
quux(4L);  // error, constructor is deleted 
quux(W{'4'}); // error, constructor is deleted 
quux(W{5}); // ok 
+0

ब्लीच, वर्दी init का अनावश्यक उपयोग। प्रत्यक्ष init प्लिक्स का प्रयोग करें। – Puppy

+2

@Puppy तुमने मुझे नीचे गिरा दिया क्योंकि मैंने ब्रेसिज़ का इस्तेमाल किया था? गंभीरता से? – Barry

+3

@ पपी बीटीडब्ल्यू, 'डब्ल्यू {5} '* * प्रत्यक्ष प्रारंभिकरण है ... – Barry

2
struct Zb { 
     Zb(long long) 
     {};  // can initialize with a long long 
     Zb(long) = delete; // but not anything smaller 
    }; 

struct Za { 
     // ... 
     explicit Za(long long) 
     {};  // can initialize ONLY with a long long 
    }; 

int main() 
{ 
    Za((long long)10); // works 
    Za((long)10);  // works  

    Zb((long long)10); // works 
    Zb((long)10);  // does not work 

    return 0; 
} 

आपका उदाहरण स्पष्ट हटाने की आवश्यकता है।

लाइव: http://cpp.sh/4sqb

1

वे ही नहीं हैं।

मानक काम मसौदा n4296 से:

12.3.1 - [class.conv.ctor]:
एक निर्माता समारोह-विनिर्देशक स्पष्ट बिना घोषित अपने वर्ग के प्रकार के लिए अपनी मापदंडों के प्रकार से एक रूपांतरण को निर्दिष्ट करता है । इस तरह के एक कन्स्ट्रक्टर को कन्स्ट्रक्टर परिवर्तित करने के लिए कहा जाता है।

एक स्पष्ट निर्माता सिर्फ गैर स्पष्ट कंस्ट्रक्टर्स की तरह वस्तुओं का निर्माण करती है, लेकिन ऐसा नहीं करता है केवल जहां डायरेक्ट-प्रारंभ वाक्य रचना (8.5) या जहां डाले (5.2.9, 5.4) स्पष्ट रूप से किया जाता है। एक डिफ़ॉल्ट कन्स्ट्रक्टर एक स्पष्ट निर्माता हो सकता है; ऐसे कन्स्ट्रक्टर का उपयोग डिफ़ॉल्ट-प्रारंभिकरण या वैल्यूनिलाइजेशन (8.5) करने के लिए किया जाएगा।

क्रमशः हर एक का एक उदाहरण इसके बाद:

struct X { 
    X(int); 
    X(const char*, int =0); 
    X(int, int); 
}; 

void f(X arg) { 
    X a = 1;  // a = X(1) 
    X b = "Jessie"; // b = X("Jessie",0) 
    a = 2;   // a = X(2) 
    f(3);   // f(X(3)) 
    f({1, 2});  // f(X(1,2)) 
} 

स्पष्ट निर्माता के साथ:

struct Z { 
    explicit Z(); 
    explicit Z(int); 
    explicit Z(int, int); 
}; 

Z a;      // OK: default-initialization performed 
Z a1 = 1;     // error: no implicit conversion 
Z a3 = Z(1);    // OK: direct initialization syntax used 
Z a2(1);     // OK: direct initialization syntax used 
Z* p = new Z(1);   // OK: direct initialization syntax used 
Z a4 = (Z)1;    // OK: explicit cast used 
Z a5 = static_cast<Z>(1); // OK: explicit cast used 
Z a6 = { 3, 4 };   // error: no implicit conversion 
5

explicit ब्लॉक निहित रूपांतरण अपने प्रकार करने के लिए।

आपकी =delete तकनीक long से long long पर अंतर्निहित रूपांतरण ब्लॉक करती है।

ये लगभग असंबंधित हैं।

Z z = 1L; 
Z z = 1LL; 

long और long longZ करने से एक अंतर्निहित रूपांतरण है:

4 मामलों है कि अंतर दर्शाने रहे हैं।

Z z = Z(1L); 
Z z = Z(1LL); 

एक स्पष्ट रूपांतरण long और long long से Z है।

explicit Z(long long) ब्लॉक:

Z z = 1L; 
Z z = 1LL; 

जबकि Z(long)=delete ब्लॉक:

Z z = 1L; 
Z z = Z(1L); 

explicit Z(long long) की अनुमति देता है Z z = Z(1L) क्योंकि long long को long से रूपांतरण निहित है, लेकिन Z को स्पष्ट रूपांतरण है कि बाद में होता है से संबंधित नहीं।

ध्यान दें कि explicit और =delete का मिश्रण केवल Z z=Z(1LL) आपके 4 संस्करणों के बीच मान्य है।

(उपर्युक्त मान्य प्रतिलिपि या सीटीओ को स्थानांतरित करता है; यदि नहीं, Z z=Z(...)Z z(...) और उसी निष्कर्ष के परिणाम के साथ प्रतिस्थापित करें)।