2016-10-24 3 views
5

क्या कोई मुझे यह समझने में सहायता कर सकता है कि निम्न कोड त्रुटि क्यों उत्पन्न करता है?फ़ंक्शन ऑब्जेक्ट को लपेटने के लिए std :: फ़ंक्शन का उपयोग करना

class A 
{ 
    public: 
    float& operator()() 
    { 
    return _f; 
    } 

    private: 
    float _f = 1; 
} a; 


auto& foo() 
{ 
    std::function<float()> func = a; 
    return func(); 
} 

int main() 
{ 
    std::cout << foo() << std::endl; 
} 

त्रुटि:

error: non-const lvalue reference to type 'float' cannot bind to a temporary of type 'float' 
    return func(); 
     ^~~~~~ 
1 error generated. 

यहाँ, operator() में, मैं _f के लिए एक संदर्भ लौट सकते हैं और इसके परिणामस्वरूप, मैंने सोचा था कि func() एक अस्थायी नहीं है। अगर कोई मुझे समझने में मदद करता है तो यह बहुत अच्छा होगा।

उत्तर

1

std::function<float()> func लिए, आप एक float, नहीं एक float& लौटने एक functor के रूप में func घोषणा कर रहे। चूंकि त्रुटि संदेश ने कहा, अस्थायी floatfunc() द्वारा लौटाया गया गैर-कॉन्स लैवल्यू संदर्भ से बाध्य नहीं किया जा सकता है।

उपर्युक्त घोषणा A::operator() के हस्ताक्षर से मेल नहीं खाती है जो लपेटा जा रहा है। लेकिन ध्यान दें कि A::operator() के हस्ताक्षर से मेल खाने के लिए टाइप को std::function<float&()> func में बदलें, संकलन त्रुटि को हल किया जा सकता है, लेकिन फिर हम स्थानीय चर के लिए संदर्भित एक संदर्भ वापस कर देंगे, जो यूबी की ओर जाता है।

ध्यान दें कि std::function<float()> func = a;, std::functiona की एक प्रति के साथ शुरू किया गया है। फिर func() में लिपटे A के सदस्य से संबंधित संदर्भ लौटाएगा, जो एक स्थानीय चर है। और फंक्शन foo से बाहर निकलने पर संदर्भ लटक जाएगा।

इसे कैसे ठीक करें अपने डिजाइन पर निर्भर करता है, auto& foo()auto foo() पर बदलें, यानी प्रतिलिपि द्वारा वापसी मूल्य पास करने से यूबी से बच जाएगा।

+0

मैंने ऐसा भी सोचा, क्योंकि यह ठीक से संकलित करता है, लेकिन मुझे डर है कि यह यूबी है, क्योंकि यह सही ढंग से चलने वाला प्रतीत नहीं होता है (उदाहरण के लिए यह क्रैश या प्रिंट 0)। –

+0

मुझे यह प्रश्न दिलचस्प पाया गया: यदि आप इसे 'ऑटो' और ' 'बनाते हैं, तो यह काम कर सकता है; यदि आप इसे 'ऑटो' और ' 'बनाते हैं तो यह भी काम करता है। कौनसा सही है? मुझे लगता है कि 'ऑटो' और '' एक सही है क्योंकि आपको संदर्भ द्वारा स्थानीय चर वापस नहीं करना चाहिए, है ना? –

+0

@ मार्सनमाओ हां, हमें स्थानीय संदर्भ में संदर्भ वापस नहीं करना चाहिए, बिंदु 'foo' को प्रतिलिपि द्वारा वापस लौटाया जाना चाहिए। (यह अभी भी अज्ञात है कि क्यों ओपी को संदर्भ द्वारा वापसी की आवश्यकता है।) – songyuanyao

5

समस्या std::function का उपयोग नहीं है, इसके कि आप एक संदर्भ के रूप में func() से अस्थायी float वापस जाने के लिए कोशिश कर रहे हैं। यह काम नहीं करेगा क्योंकि जैसे ही कथन समाप्त होता है, वस्तु समाप्त हो जाएगी।

यदि आप auto& foo() से auto foo() बदलते हैं तो इसे काम करना चाहिए।

+0

आप '' अपरिवर्तित छोड़ देते हैं तो क्यों, यह संकलित कर सकते हैं? 'ए' का ऑपरेटर 'फ्लोट' नहीं लौटा रहा है? –

+1

क्योंकि यह 'फ्लोट' से एक नया 'फ्लोट' प्रतिलिपि बना सकता है। – Kiskae

+0

आह, मुझे लगता है कि मैं इसे समझ गया, धन्यवाद! –

3

मुझे लगता है कि आप समझते हैं कि एक स्थानीय चर के संदर्भ को वापस करने के बाद वैरिएबल गुंजाइश से बाहर हो जाता है। हालांकि आपको लगता है कि std::function<float()> func = a; वास्तव में a से स्थानीय std::function बनाता है। यह किसी भी तरह से a पर इंगित नहीं करता है, func का अपना A है। जिसका अर्थ है कि func(); पर कॉलिंग वास्तव में a.operator() नहीं है बल्कि func के A का आह्वान नहीं करता है। फिर हम वापस स्थानीय संदर्भ में वापस आते हैं एक संदर्भ लौटने बुराई हिस्सा है।

इसे संकलित करने के लिए, आप अपना टेम्पलेट हस्ताक्षर float&() पर बदल सकते हैं लेकिन यह अभी भी अपरिभाषित व्यवहार है।

संदर्भ को हटाने के बजाय रिटर्न प्रकार को प्रतिलिपि (auto) में बदलने के लिए एक फिक्स होगा।

+0

क्यों 'std :: function func = a; 'कोई समस्या नहीं है? 'ए' का ऑपरेटर हस्ताक्षर 'फ्लोट 'नहीं है? क्या ऐसा इसलिए है क्योंकि वे संगत हैं? –

+0

@ मार्सनमाओ यह एक समस्या का कारण बनता है, एक संकलन समस्या जिसे 'फ्लोट और() 'में बदलकर तय किया जा सकता है। हालांकि, यह अभी भी यूबी का कारण बनता है। यही कारण है कि हम संदर्भ से वापस नहीं आ सकते हैं। –

+0

मैं इसे 'ऑटो foo() 'और' std :: function func = a; 'के साथ ठीक से संकलित और निष्पादित कर सकता हूं। मुझे यह दिलचस्प लगता है। क्या आप कृपया बता सकते हैं क्यों? (मैं वीएस2015 का उपयोग कर रहा हूं) –

1

ऊपर दिए गए महान उत्तरों को पढ़ने के बाद, मैंने कुछ अलग विचार देने की कोशिश की।

मुझे लगता है कि ओपी वास्तव में एक निश्चित वस्तु के float& को वापस करना चाहता है (जो ओपी के उदाहरण में a है)।

तो अगर ओ पी चाहता है foo वापस जाने के लिए auto& (जो एक float& होना चाहिए), तो यह निम्नलिखित के रूप में किया जाना चाहिए, कृपया std::bind भाग पर ध्यान दें:

namespace T1 
{ 
class A 
{ 
public: 
    float& operator()() 
    { 
     std::cout << "a add = " << this << std::endl; 
     return _f; 
    } 

    float getF() { return _f; } 

private: 
    float _f = 1; 
} a; 

auto& foo() 
{ 
    std::function<float&()> func = std::bind(&A::operator(), &a); 
    return func(); 
} 
} // end of namespace T1 

int main() 
{ 
    std::cout << "global a add = " << &(T1::a) << std::endl; // check a's address 
    float& f = T1::foo(); // note that `a`'s address is the same 
    std::cout << f << std::endl; // still 1 
    f = 777; 
    std::cout << f << std::endl; // now 777 
    std::cout << T1::a.getF() << std::endl; // it's 777 

    return 0; 
} 
संबंधित मुद्दे