2010-05-05 11 views
11
class Foo 
{ 
public: 
    explicit Foo() {} 
    explicit Foo(Foo&) {} 
}; 

Foo d = Foo(); 

error: no matching function for call to 'Foo::Foo(Foo)'फू एफ = फू(); // 'Foo :: Foo (Foo)' पर कॉल करने के लिए कोई मिलान करने वाला फ़ंक्शन नहीं ... हुह?

मैं Foo(Foo) के रूप में त्रुटि पता चलता है करने के लिए Foo(Foo&) बदलते कोशिश की, जो AFAIK एक वैध निर्माता नहीं है, और यकीन है कि पर्याप्त मैं:

error: invalid constructor; you probably meant ‘Foo (const Foo&)’

क्या देता है? मैं इसका कैसे समाधान करूं? (यह जीसीसी पर है)

+1

फू फू फू? है ना? –

+2

कंपाइलर ने पहले से ही आपके प्रश्न का उत्तर दिया है ... 'फू (कॉन्स फू एंड) '। 'फू डी = फू();' कॉपी कन्स्ट्रक्टर का आह्वान कर रहा है। –

+3

+1 क्योंकि कोई भी जवाब –

उत्तर

12

आपके प्रतिलिपि बनाने वाले दो संदिग्ध चीजें हैं जो आपके पास हैं।

सबसे पहले, आप कॉपी-निर्माता स्पष्ट है (जो कि एक संदिग्ध बात है) के बाद, आप (सिद्धांत में) होगा क्या करने की जरूरत है ताकि:

Foo d((Foo())); 

दूसरा, आपके प्रति निर्माता लेता है एक संदर्भ और const संदर्भ नहीं है जिसका अर्थ है कि आप इसे अस्थायी Foo के साथ उपयोग नहीं कर सकते हैं।

व्यक्तिगत रूप से, मैं कॉपी-कन्स्ट्रक्टर से explicit हटा दूंगा और यदि संभव हो तो इसे const संदर्भ लेगा।

ध्यान दें कि आपके डिफ़ॉल्ट कन्स्ट्रक्टर पर explicit का कोई प्रभाव नहीं पड़ता है। [*] explicit केवल रचनाकारों पर प्रभाव डालता है जिसे एकल पैरामीटर के साथ बुलाया जा सकता है। यह उन्हें निहित रूपांतरणों के लिए इस्तेमाल करने से रोकता है। रचनाकारों के लिए जो केवल शून्य या केवल दो या अधिक पैरामीटर लेते हैं, इसका कोई प्रभाव नहीं पड़ता है।

[नोट: के बीच एक अंतर हो सकता है:।

Foo d; 

और

Foo d = Foo(); 

लेकिन इस मामले में आप एक उपयोगकर्ता के घोषित डिफ़ॉल्ट निर्माता तो यह लागू नहीं होता है]

संपादित करें: [*] मैंने इसे दो बार चेक किया है और 12.3.1 [class.conv.ctor] कहता है कि आप एक डिफ़ॉल्ट विपक्ष बना सकते हैं ट्रक्टर explicit। इस मामले में कन्स्ट्रक्टर का उपयोग डिफ़ॉल्ट-प्रारंभिक या मूल्य-प्रारंभिक करने के लिए किया जाएगा।ईमानदार होने के लिए, मुझे इस बात का एहसास नहीं है कि आपके पास उपयोगकर्ता द्वारा घोषित कन्स्ट्रक्टर है, तो यह गैर-पीओडी प्रकार है और यहां तक ​​कि गैर-पीओडी प्रकार की स्थानीय वस्तुएं डिफ़ॉल्ट-प्रारंभिक हैं यदि उनके पास प्रारंभकर्ता नहीं है जो इस खंड का कहना है explicit डिफ़ॉल्ट कन्स्ट्रक्टर द्वारा किया जा सकता है। शायद कोई एक कोने केस इंगित कर सकता है जहां यह कोई फर्क पड़ता है लेकिन अभी के लिए मुझे नहीं लगता कि explicit का डिफ़ॉल्ट कन्स्ट्रक्टर पर क्या प्रभाव पड़ता है।

+1

ब्रांड्स का अतिरिक्त सेट क्यों? – clahey

+2

@clahey: सबसे अधिक परेशान पार्स के आसपास पाने के लिए। –

+4

अब जेम्स ने सही जवाब दिया है, मैं बस इतना कह सकता हूं: क्योंकि मैं एक कोठरी लापरवाही प्रशंसक हूं। –

2

आपकी समस्या तत्काल में है। आपको डिफ़ॉल्ट कन्स्ट्रक्टर के लिए Foo d = Foo(); की आवश्यकता नहीं है।

अपनी कक्षा में एक ही रखें, लेकिन इन्स्टेन्शियशन के लिए इस प्रयास करें:

Foo d; 

वास्तव में, आप भी Foo d = Foo(arguments); मानकों के साथ निर्माण के लिए जरूरत नहीं है। यही कारण है कि इस तरह से किया जाना चाहिए:

Foo d(arguments); 
+0

'फू डी = फू()' त्रुटि उत्पन्न करने के लिए सिर्फ एक सरलीकरण था। मैं 'फू डी;' और 'फू के = डी;' कहीं और – Kyle

+0

@ केली: कई टिप्पणियों से अब आप छोड़ चुके हैं, मैं देख सकता हूं कि आप जानबूझकर कॉपी कन्स्ट्रक्टर का आह्वान करने की कोशिश कर रहे थे। काश आप अपने प्रश्न में इतनी स्पष्ट रूप से कहा था। मुझे आपके प्रश्न में कहीं भी नहीं मिल रहा है कि आप यह कहते हैं कि आप यह भी जानते हैं कि एक प्रतिलिपि बनाने वाला * क्या है; आपने अभी कोड पोस्ट किया है और कहा है "यह ब्रोकेंस क्यों है?" मैंने धारणा बनाई (हाँ, हाँ) कि आप बस इसे गलत कर रहे थे। 'फू डी = फू();' निश्चित रूप से उस बेड़े 'फू' उदाहरण पर कॉपी कन्स्ट्रक्टर को आमंत्रित करता है, लेकिन ऐसा कुछ ऐसा है जो आपको वास्तव में * नहीं करना चाहिए। – Randolpho

+0

जैसा कि इसके शीर्षक में बताया गया है, मेरा प्रश्न विचित्र त्रुटि संदेश के बारे में है, जो दिए गए कोड से स्पष्ट परिणाम प्रतीत नहीं होता है। मैंने अभी तक एक प्रश्न को हल करने के कौशल को महारत हासिल नहीं किया है ताकि कोई भी गलत प्रश्न का उत्तर दे सके। कृपया अपना उत्तर संपादित करें ताकि मुझे आपको ऊपर उठाने की अनुमति मिल सके। – Kyle

2
Foo d = Foo(); 

होना चाहिए

Foo d; 

पहली पंक्ति एक फू उदाहरण बनाता है और फिर घ के लिए प्रतियां यह;

+0

सही, लेकिन प्रश्न का उत्तर नहीं - 'Foo d = Foo() 'त्रुटि उत्पन्न करने के लिए केवल एक सरलीकरण था। मैं कहीं और 'फू डी' 'और 'फू के = डी;' कहीं और हो सकता था। – Kyle

3

स्पष्ट के बिना प्रयास करें? मुझे लगता है कि:

Foo foo = Foo() 

एक निहित प्रति बनाता है, इस प्रकार स्पष्ट प्रतिलिपि निर्माता ट्रिगर नहीं होता है।

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

यह केवल आधा जवाब है। चार्ल्स बेली या अंकलबेन्स पोस्ट देखें क्योंकि क्यों आवश्यक है।

+1

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

+1

यह आधा जवाब है। – clahey

1

संकलक आपको बता रहा है ... इस का उपयोग करें:

Foo(const Foo&) {} 
+0

काउंटर डाउन-वोट। यह सचमुच बता रहा है कि हस्ताक्षर कैसा दिखना चाहिए। (ऐसा नहीं करना चाहिए - कुछ नहीं - हालांकि।) – UncleBens

5

आप स्पष्ट रूप में उन निर्माताओं में से किसी को चिह्नित नहीं करना चाहते - संकलक उन दोनों को, विशेष रूप से प्रतिलिपि निर्माता का उपयोग करने की जरूरत है, परोक्ष। आप उन्हें स्पष्ट रूप से चिह्नित करके प्राप्त करने की क्या कोशिश कर रहे हैं?

+0

अपने प्रश्न का उत्तर देने के लिए: मैं किसी ऐसे रूपांतरण के कारण किसी भी सुपरराइज को खत्म करना चाहता हूं जो मैं नहीं करना चाहता था (... संकलक को त्रुटि उत्पन्न करने के द्वारा)। – Kyle

+1

@ केली लेकिन आप चाहते हैं कि संकलक प्रतिलिपि बनाने में सक्षम हो - यह रूपांतरण नहीं है। और न ही डिफ़ॉल्ट निर्माण है। –

+0

ठीक है, लेकिन अगर मैं कभी भी 'Foo f = Bar()' करने का प्रयास करता हूं, तो मैं इसे बम करना चाहता हूं, जहां 'बार' खुशी से खुद को 'ऑपरेटर फू()' प्रदान करके एक फू में परिवर्तित करने की अनुमति देता है (मुझे लगता है कि मेरे पास है उस विचार को सही सही ..) – Kyle

0

आप समस्या को दो तरीकों से ठीक कर सकते हैं। एक (पहले से ही रैंडोल्फो द्वारा सुझाया गया) कॉपी सीटीआर का उपयोग करके खत्म करना है। दूसरा एक उचित प्रतिलिपि लिखना है:

Foo (Foo const &) {} 

आप आम तौर पर दोनों करना चाहते हैं।

संपादित करें: इसे देखकर, मेरी आखिरी टिप्पणी गलत-कन्स्ट्रू करना आसान है। काफी कुछ कक्षाएं पर एक प्रतिलिपि ctor की आवश्यकता नहीं है, लेकिन यदि आपको एक प्रतिलिपि ctor की आवश्यकता है, तो सामान्य रूप से ऊपर का फॉर्म होना चाहिए (स्पष्ट नहीं है, और पैरामीटर के रूप में कॉन्स्ट संदर्भ लेना चाहिए)।

+0

'फू (फू एंड)' एक उचित प्रतिलिपि निर्माता है। वह जो भी करने की कोशिश कर रहा है उसके लिए यह सही कॉपी कन्स्ट्रक्टर नहीं है। –

+0

@ डेनिस: यदि आपको यह पसंद है, तो यह ठीक है - लेकिन एक कॉपी कन्स्ट्रक्टर जो प्रतिलिपि बनाने वाली वस्तु को संशोधित करने के लिए दरवाजा खोलता है वह वह नहीं है जिसे मैं "उचित" कहूंगा। –

-1
class Foo 
{ 
public: 
    explicit Foo() {} 
    explicit Foo(const Foo&) {} 
}; 

Foo d = Foo() 
+0

नकारात्मक 1 क्यों? – Betamoo

+0

यह मैं नहीं था, लेकिन मैं आपको बता सकता हूं कि अभी भी संकलित नहीं है। – Kyle

3

एक प्रति निर्माता स्पष्ट (जो इसे यहाँ और इस तरह जब गुजर या मूल्य से लौटने के रूप में कई अन्य पूरी तरह से उचित संदर्भों में uncallable बनाता है) नहीं होना चाहिए।

अगला इसे कॉन्स संदर्भ से तर्क लेना चाहिए, अन्यथा यह अस्थायी से बंधे नहीं जा सकता है।

Foo f = Foo(); 
     ^^^^^ 
      | 
      --- this is a temporary that cannot be passed to a function 
       that accepts a non-const reference 

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

Foo f; 
f = 1; //assuming no operator= overload for (types convertible from) int 
     //this implicitly performs f = Foo(1); 

Foo g = 10; 

void x(Foo); 
x(20); 

सभी सब में:

class Foo 
{ 
public: 
    Foo(); 
    Foo(const Foo&); 
    //... 
}; 

Foo x = Foo(); 

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

+0

यह अब तक का सबसे अच्छा जवाब है, लेकिन मैं सही काम करने के बारे में और अधिक टेक्स्ट जोड़ूंगा। – clahey

+0

आप सीधे प्रारंभिकरण का उपयोग कर एक स्पष्ट प्रतिलिपि निर्माता को कॉल कर सकते हैं (उदा।, 'Foo f; Foo g (f); ')। –

+0

@ जेम्स: धन्यवाद, एक स्पष्टीकरण जोड़ा गया। – UncleBens

4

पहला, न तो डिफ़ॉल्ट कन्स्ट्रक्टर और न ही प्रतिलिपि निर्माता कभी भी explicit होना चाहिए। आपको केवल उस प्रकार से निहित रूपांतरण को रोकने के लिए, किसी अन्य प्रकार का एक तर्क लेता है, तो आपको केवल explicit का निर्माण करने की आवश्यकता है। कॉपी कन्स्ट्रक्टर कक्षा के लिए एक संदर्भ लेता है, इसलिए अवांछित रूपांतरण का कोई खतरा नहीं है।

दूसरा, सुनिश्चित करें कि कॉपी कन्स्ट्रक्टर const संदर्भ लेता है।

तीसरा, Foo f; कक्षा foo का डिफ़ॉल्ट-निर्मित ऑब्जेक्ट रखने का सही तरीका है। ध्यान दें कि Foo f(); गलत है, क्योंकि संकलक इसे f() फ़ंक्शन की घोषणा के रूप में व्याख्या करेगा जो Foo वर्ग का ऑब्जेक्ट देता है।

चौथा, यदि आपने अपनी प्रतिलिपि निर्माता लिखा है, तो आपको असाइनमेंट ऑपरेटर भी लिखना चाहिए।

 

class Foo 
{ 
    Foo() {} // no need to make explicit. Nothing to convert from. 

    Foo(const &Foo f) {} // again, nothing wrong with conversion from Foo to Foo 

    explicit Foo(int a) {} // need explicit to prevent accidental passing of an int 
          // to a function that takes Foo as an argument 
}; 
 
संबंधित मुद्दे