2012-04-26 15 views
5

मुझे वास्तव में सी # में गुणों का विचार पसंद है, और थोड़ी सी साइड प्रोजेक्ट के रूप में, मैं सी ++ में उन्हें लागू करने के विचार से टंकण कर रहा हूं। मैं इस उदाहरण में भाग गया https://stackoverflow.com/a/5924594/245869 जो काफी अच्छा लगता है, लेकिन मैं मदद नहीं कर सका लेकिन लगता है कि लैम्ब्डा और गैर स्थैतिक डेटा सदस्य प्रारंभिकरण इस विचार के साथ कुछ बहुत अच्छे वाक्यविन्यास का उपयोग करना संभव कर सकता है।सी ++ 11; क्या गैर स्थैतिक डेटा सदस्य प्रारंभिक अन्य डेटा सदस्यों तक पहुंच सकते हैं?

#include <iostream> 
#include <functional> 

using namespace std; 


template< typename T > 
class property { 

public: 
    property(function<const T&(void)> getter, function<void(const T&)> setter) 
     : getter_(getter), 
      setter_(setter) 
    {}; 

    operator const T&() { 
     return getter_(); 
    }; 

    property<T>& operator=(const T& value) { 
     setter_(value); 
    } 

private: 
    function<const T&(void)> getter_; 
    function<void(const T&)> setter_; 

}; 


class Foobar { 

public: 
    property<int> num { 
     [&]() { return num_; }, 
     [&](const int& value) { num_ = value; } 
    }; 

private: 
    int num_; 

}; 


int main() { 
    // This version works fine... 
    int myNum; 
    property<int> num = property<int>(
     [&]() { return myNum; }, 
     [&](const int& value) { myNum = value; } 
    ); 
    num = 5; 

    cout << num << endl; // Outputs 5 
    cout << myNum << endl; // Outputs 5 again. 

    // This is what I would like to see work, if the property 
    // member of Foobar would compile... 
    // Foobar foo; 
    // foo.num = 5; 

    // cout << foo.num << endl; 

    return 0; 
} 

मैं अपनी संपत्ति वर्ग सामान्य रूप से उपयोग कर सकते हैं एक डेटा के रूप में संपत्ति का उपयोग करने में है, लेकिन जी ++ 4.7 के साथ MinGW विशेष रूप से मेरे प्रयास की परवाह नहीं करता [में मुख्य() उदाहरण देखें]: यहाँ मेरी कार्यान्वयन है सदस्य:

\property.cpp: In lambda function: 
\property.cpp:40:7: error: invalid use of non-static data member 'Foobar::num_' 

तो यह मेरी संपत्ति कार्यान्वयन की अवधारणा काम करता है लगता है, लेकिन यह व्यर्थ में हो सकता है क्योंकि मैं अपने लैम्ब्डा कार्यों से अन्य डेटा के सदस्यों तक नहीं पहुँच सकता। मुझे यकीन नहीं है कि मानक कैसे परिभाषित करता है कि मैं यहां क्या करने की कोशिश कर रहा हूं, क्या मैं पूरी तरह भाग्य से बाहर हूं, या क्या मैं यहां कुछ नहीं कर रहा हूं?

+3

असंबद्ध: आप शायद चालक में 'getter_ (std :: move (getter)), setter_ (std :: move (setter))' चाहते हैं, केवल चाल प्रकारों का समर्थन करने के लिए, और सामान्य रूप से अपर्याप्त प्रतियों से बचें। –

+0

प्रश्न: मनोरंजक होने के अलावा, मुझे विश्वास है कि एक सरल 'int' 'और अधिक उपयोगी होगा। एक साधारण संदर्भ पर आपके समाधान का क्या फायदा है? (जो स्वयं बेकार है ...) –

+0

@ आर। मार्टिन्हो फर्नांडीस मैं पूरी तरह से सहमत हूं। 'संपत्ति <>' को स्वयं कॉपी/मूव सेमेन्टिक्स का समर्थन करने की भी आवश्यकता है ताकि गुणों वाले वर्गों की प्रतिलिपि बनाई जा सके। मैं कार्यान्वयन को तब तक कम से कम रखना चाहता था जब तक कि मैं अवधारणा को काम नहीं कर पाता। हालांकि धन्यवाद! –

उत्तर

2

आपकी संपत्ति एक अलग वस्तु (property<int> का उदाहरण) युक्त वस्तु (Foobar का उदाहरण) से है। इस प्रकार, इसके सदस्य कार्य this को पारित करते हैं, न कि आपको num_ तक पहुंचने की आवश्यकता होगी - ताकि आप इसे इस तरह से नहीं कर सकें। यदि लैम्ब्डा को Foobar के गैर-स्थैतिक सदस्य फ़ंक्शन में परिभाषित किया गया था, तो वे उस फ़ंक्शन के this तर्क पर कब्जा कर लेते थे और उन्हें संलग्न वस्तु के सदस्यों (स्पष्ट रूप से, this->num_) तक पहुंच प्राप्त होती। लेकिन भेड़ के बच्चे को कक्षा में परिभाषित किया जाता है, जहां गैर स्थैतिक डेटा सदस्य वास्तव में मौजूद नहीं होते हैं। यदि lambdas पर num_ तक पहुंच है, जो num_ है, जिसमें से Foobar का उदाहरण है, तो क्या होगा?

सबसे आसान समाधान जो मैं देखता हूं वह संपत्ति के लिए संलग्न वस्तु को पॉइंटर स्टोर करने के लिए है। इस तरह, यह अपने गैर स्थैतिक सदस्यों को आसानी से एक्सेस कर सकता है। नकारात्मकता यह है कि घोषणा थोड़ा अधिक जटिल है (आपको property<int, Foobar> num करना होगा) और आपको this पॉइंटर पास करके संपत्ति को प्रारंभ करना होगा। तो आप कक्षा में ऐसा करने में सक्षम नहीं होंगे, इसे कन्स्ट्रक्टर की प्रारंभिक सूची में होना होगा, इसलिए सी ++ 11 के डेटा सदस्य प्रारंभिकरण के लाभ को अस्वीकार करना होगा।

उस बिंदु पर, this लैम्बडास के लिए वैसे भी कैप्चर करने के लिए उपलब्ध होगा (मूल्य के अनुसार, संदर्भ द्वारा नहीं!) तो आपका कोड वास्तव में कम से कम परिवर्तनों के साथ काम करेगा, अगर आपने संपत्ति को प्रारंभ करने के लिए फूबर के निर्माता (एस):

Foobar::Foobar(): 
    num { 
     [this]() { return this->num_; }, 
     [this](const int& value) { this->num_ = value; } 
    } 
{ 
} 

किसी को भी पता है कि क्या this, के रूप में करने के लिए जो कुछ भी निर्माता लागू किया जा करने के लिए होता पारित कर दिया, वर्ग परिभाषा गैर स्थिर सदस्य आरंभीकरण के लिए उपलब्ध है? मुझे संदेह है कि यह नहीं है, लेकिन यदि यह था, तो वही निर्माण वर्ग परिभाषा के अंदर काम करेगा।

+0

मैं बस एक और सामान्य समस्या जोड़ना चाहता था, जिसमें यह एक विशेष मामला है, अर्थात् किसी ऑब्जेक्ट से संलग्न वस्तु तक पहुंच, आंतरिक वस्तु में बाहरी वस्तु को पॉइंटर संग्रहीत किए बिना, सी ++ में हमेशा मुश्किल रहा है। यह किया जा सकता है, लेकिन यह अच्छा नहीं लग रहा है और मुझे यकीन है कि पॉइंटर जादू में सख्त-एलियासिंग नियमों को तोड़ दिया गया है ... – cvoinescu

+0

मुझे इस सवाल पूछने के एक घंटे बाद पता चला कि कैप्चर क्लॉज [यह] फिक्स डेटा सदस्यों तक पहुंच, मुझे यकीन नहीं था कि यह क्यों जरूरी था, लेकिन आपका जवाब मेरे लिए इसे साफ़ करता है। धन्यवाद! यह पता चला है कि आपको इसे कन्स्ट्रक्टर की प्रारंभिक सूची में स्थानांतरित करने की आवश्यकता नहीं है। कोड के साथ कैप्चर क्लॉज को बदलना क्योंकि मैंने इसे पूरी तरह से काम किया था। –

+0

एक लम्बी समस्या है, हालांकि, जो मेरे मूल प्रश्न से काफी संबंधित नहीं है। आपके द्वारा समझाए गए कारणों के कारण, लैम्बडास मेरे 'फूओबर' वर्ग के निजी डेटा सदस्यों तक पहुंचने में सक्षम नहीं हैं। मुझे इस काम को करने के लिए 'Foobar' से''संपत्ति को सही तरीके से मित्रवत करने का तरीका नहीं पता है। डेटा सदस्यों को 'सार्वजनिक' संकलन में सेट करना और पूरी तरह से चलता है, इसलिए मुझे लगता है कि friending समाधान है। –

संबंधित मुद्दे