2012-08-13 6 views
19

इस तरह एक वर्ग होने:लैम्बडा में निजी विधि का उपयोग करना क्यों संभव नहीं है?

class A { 
public: 
    bool hasGrandChild() const; 

private: 
    bool hasChild() const; 
    vector<A> children_; 
}; 

क्यों यह एक लैम्ब्डा अभिव्यक्ति विधि hasGrandChild() इस तरह के रूप में परिभाषित में एक निजी विधि hasChild() उपयोग करने के लिए संभव नहीं है?

bool A::hasGrandChild() const { 
    return any_of(children_.begin(), children_.end(), [](A const &a) { 
     return a.hasChild(); 
    }); 
} 

संकलक कि विधि hasChild() संदर्भ में निजी है एक त्रुटि जारी करता है। क्या कोई कामकाज है?

संपादित करें: ऐसा लगता है कि जिस कोड को मैंने पोस्ट किया है वह मूल रूप से काम करता है। मैंने सोचा था कि यह बराबर है, लेकिन कोड है कि does not work on GCC अधिक इस तरह है:

#include <vector> 
#include <algorithm> 

class Foo; 

class BaseA { 
protected: 
    bool hasChild() const { return !children_.empty(); } 
    std::vector<Foo> children_; 
}; 

class BaseB { 
protected: 
    bool hasChild() const { return false; } 
}; 

class Foo : public BaseA, public BaseB { 
public: 
    bool hasGrandChild() const { 
    return std::any_of(children_.begin(), children_.end(), [](Foo const &foo) { 
     return foo.BaseA::hasChild(); 
     }); 
    } 
}; 

int main() 
{ 
    Foo foo; 
    foo.hasGrandChild(); 
    return 0; 
} 

लगता है वहाँ this does not work, लेकिन this works के रूप में पूरी तरह से योग्य नाम के साथ एक समस्या है।

+1

बंद प्रकार अपनी कक्षा 'A' से कोई संबंध नहीं है, इसलिए स्वाभाविक रूप से यह' A' के गैर सरकारी सदस्यों का उपयोग नहीं कर सकते हैं। न ही यह कभी भी हो सकता है, क्योंकि इसका प्रकार नाम अज्ञात है, इसलिए आप इसे 'मित्र' भी नहीं बना सकते हैं। –

+2

क्या यह सिर्फ मुझे है या यह काम gcc पर करता है? http://ideone.com/333qw – pmr

+0

@pmr: हाँ यह पुराने जीसीसी में काम करता प्रतीत होता है, लेकिन नए में काम नहीं करता है। –

उत्तर

27

यह एक विशेष मामले में सिर्फ एक जीसीसी बग जब लैम्ब्डा माता पिता वर्ग से एक संरक्षित सदस्य पूरी तरह से योग्य नाम का उपयोग कर का उपयोग करने की कोशिश करता है लगता है। This does not work:

class Base { 
protected: 
    bool hasChild() const { return !childs_.empty(); } 
    std::vector<Foo> childs_; 
}; 

class Foo : public Base { 
public: 
    bool hasGrandChild() const { 
    return std::any_of(childs_.begin(), childs_.end(), [](Foo const &foo) { 
     return foo.Base::hasChild(); 
    }); 
    } 
}; 

, लेकिन this works:

class Foo : public Base { 
public: 
    bool hasGrandChild() const { 
    return std::any_of(childs_.begin(), childs_.end(), [](Foo const &foo) { 
     return foo.hasChild(); 
    }); 
    } 
}; 

सी ++ 11 के अनुसार, 5.1.2/3:

लैम्ब्डा अभिव्यक्ति के प्रकार (जो भी है क्लोजर ऑब्जेक्ट का प्रकार) एक अद्वितीय, अज्ञात गैर-यूनियन क्लास प्रकार है - जिसे क्लोजर प्रकार कहा जाता है - जिनकी गुण नीचे वर्णित हैं। यह वर्ग प्रकार कुल नहीं है (8.5.1)। बंद करने का प्रकार में सबसे छोटा ब्लॉक स्कोप, क्लास स्कोप, या नेमस्पेस स्कोप में घोषित किया गया है जिसमें संबंधित लैम्ब्डा-अभिव्यक्ति शामिल है।

और फिर सी ++ 11, 11.7/1:

एक नेस्टेड वर्ग एक सदस्य है और के रूप में ऐसी किसी अन्य सदस्य के रूप में ही पहुँच अधिकार नहीं है।

तो उल्लिखित कार्य-स्थानीय लैम्ब्डा के पास कक्षा के किसी अन्य सदस्य के समान पहुंच अधिकार होना चाहिए। इसलिए यह एक अभिभावक वर्ग से संरक्षित विधि को कॉल करने में सक्षम होना चाहिए।

+1

इस बारे में महान स्पष्टीकरण क्यों * काम करना चाहिए। (और यहां अन्य अधिकांश उत्तरों गलत क्यों हैं।) +1 – etherice

0

यह संभव नहीं है क्योंकि लैम्ब्डा कक्षा का हिस्सा नहीं है। यह एक ऑफ-ऑफ-क्लास फ़ंक्शन बनाने जैसा है, और इसे लैम्ब्डा बनाने के बजाए बुला रहा है। बेशक इसका निजी सदस्यों तक पहुंच नहीं है।

9

मानक (सी ++ 11, §5.1.2/3), कहा गया है कि

लैम्ब्डा अभिव्यक्ति के प्रकार (जो भी बंद वस्तु के प्रकार है) एक अद्वितीय है अज्ञात गैर-संघ वर्ग प्रकार - बंद प्रकार कहा जाता है।

के बाद से यह एक अद्वितीय वर्ग प्रकार है कि A के friend नहीं है है, यह A के निजी सदस्यों के लिए उपयोग नहीं है।

यहां कंपाइलर क्या क्लास प्रकार बनाता है जिसमें किसी भी कैप्चर किए गए चर, उचित operator() इत्यादि को स्टोर करने के लिए उचित सदस्य हैं - यदि आप सी ++ 03 में लैम्ब्स को अनुकरण करना चाहते हैं तो आप खुद को लिखेंगे। इस प्रकार के पास निश्चित रूप से private सदस्यों तक पहुंच नहीं होगी, जो यह देखने में आसान हो सकता है कि सीमा क्यों है और कोई वर्कअराउंड क्यों नहीं है।

अद्यतन के बारे में संभावित समाधानों:

बेहतर होगा कि कहने के लिए है, क्योंकि सामान्य समाधान में मौजूद है, हालांकि वे अपेक्षा करते हैं कि आप सुविधाजनक लैम्ब्डा वाक्यविन्यास छोड़ "कोई एक लैम्ब्डा का उपयोग कर कामकाज से जुड़े हैं"। उदाहरण के लिए, आप कर सकते हैं:

  1. एक स्थानीय वर्ग प्रकार है कि स्पष्ट रूप से किसी अन्य स्थानीय लोग इसे की आवश्यकता है (नीचे ब्योर्न Pollex की टिप्पणी से प्रेरित) के साथ-साथ this कब्जा लिखें।
  2. लैम्ब्डा के बजाय private विधि लिखें और कॉलबैक के रूप में पास करें (उदाहरण के लिए std::bind सुविधा के लिए)। यदि आप this के अतिरिक्त स्थानीय लोगों को कैप्चर करना चाहते हैं तो आप ऐसा करने के लिए कॉल साइट पर std::bind का उपयोग कर सकते हैं।
+2

हालांकि यह स्थानीय 'संरचना' के साथ काम करता है (http://ideone.com/AvsBE)। क्या आप अंतर समझा सकते हैं? –

+0

@ BjörnPollex: यह एक * स्थानीय * 'संरचना' है, यही कारण है कि इसके पास इसके प्रकार के निजी सदस्यों तक पहुंच है (पुस्तक को उद्धृत करना: * स्थानीय वर्ग संलग्न गुंजाइश के दायरे में है, और उसी है समारोह के बाहर नामों तक पहुंच के रूप में संलग्न कार्य करता है। *)। आप कह सकते हैं कि यह एक कार्यात्मक कामकाज हालांकि है। – Jon

+0

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

3

वर्कअराउंड:

typedef bool (A::*MemFn)(void) const; 

bool A::hasGrandChild() const { 
    MemFn f = &A::hasChild; 
    return any_of(childs_.begin(), childs_.end(), [=](A const &a) { 
      return (a.*f)(); 
    }); 
} 
+1

रुको। क्यों बिल्ली आप 'any_of (शुरू, अंत, std :: mem_fn (& A :: hasChild)) की तुलना में नहीं करेंगे? मामूली प्रदर्शन जुर्माना के अलावा। – pmr

+0

@pmr - यह मुख्य रूप से यह वर्णन करने के लिए है कि लैम्ब्डा अभिव्यक्तियों में निजी सदस्य कार्यों का उपयोग कैसे करें। – Henrik

+0

@ अपराह्न: प्रदर्शन जुर्माना? मैं एक की उम्मीद नहीं करता; यह एक उचित संकलक के लिए काफी स्पष्ट है कि 'f' नहीं बदलता है। – MSalters

3

आप स्पष्ट रूप से this पर कब्जा कर सकते हैं और इसे "सदस्य लैम्ब्डा" बना सकते हैं जिसके पास निजी सदस्यों तक पहुंच है।

उदाहरण के लिए, निम्न नमूना पर विचार करें:

#include <iostream> 
class A { 
private: 
    void f() { std::cout << "Private"; } 
public: 
    void g() { 
     [this] { 
      f(); 
      // doesn't need qualification 
     }(); 
    } 
}; 
class B { 
private: 
    void f() { std::cout << "Private"; } 
public: 
    void g() { [] { f(); }(); } // compiler error 
}; 
int main() { 
    A a; 
    a.g(); 
}