2010-12-02 11 views
6

मैं सी ++ में एक संरचना (या कुछ समान) रखना चाहता हूं, जो इसके सदस्यों को गतिशील रूप से एक्सेस करने की अनुमति देगा। इसमें एक सामान्य गेटर और सेटर्स होना चाहिए जो सदस्य नाम को स्ट्रिंग के रूप में प्राप्त करते हैं, और कुछ प्रकार के संस्करण प्रकार (उदा। boost::variant) लौटाते हैं।सी ++ संरचना में सदस्यों को गतिशील रूप से और स्थिर रूप से

मुझे लगता था कि यह प्रत्येक सदस्य के नाम का प्रतिनिधित्व करने वाली स्ट्रिंग जोड़कर boost::fusion::map का उपयोग करके कार्यान्वित किया जा सकता है, और स्ट्रिंग्स और गेटर या सेटर फ़ंक्शंस के बीच एक एसटीएल मानचित्र बनाकर लागू किया जा सकता है। मैं पहिया को फिर से शुरू नहीं करना चाहता, इसलिए मैं उम्मीद कर रहा था कि ऐसा कुछ पहले से मौजूद है।

आपको क्या लगता है? क्या मेरा विचार काम करेगा? क्या आप मेरे लक्ष्य को पूरा करने के अन्य तरीकों को जानते हैं?

धन्यवाद, हाग्गै

+2

मुझे आश्चर्य है कि आप यह क्यों चाहते हैं? यहां तक ​​कि उन भाषाओं में भी जो सीधे इसका समर्थन करते हैं, प्रतिबिंब एक हैक है जो खराब कोड, या आलसी प्रोग्रामर के लिए सस्ता कोड प्राप्त करने के लिए उपयोग किया जाता है। –

+0

आप टाइप-सुरक्षा सी ++ को हरा रहे हैं आपको देता है। पृथ्वी पर क्या अनिश्चितता प्राप्त करने के लिए एक गन्दा हैक के साथ शुद्धता के लिए इस तरह के एक सरल, मजबूत उपकरण का आदान-प्रदान करने का औचित्य साबित कर सकता है? – wilhelmtell

+0

@ विल्हेल्मटेल: मैं सही संतुलन खोजने की कोशिश कर रहा हूं। मैं एक बहुत ही अनिश्चित स्रोत से मूल्य पढ़ रहा हूं, और उन्हें एक सामान्य तरीके से पार्स और संभालने की आवश्यकता है। केवल उनमें से एक छोटे से हिस्से के लिए मुझे सही प्रकार पता है (और जानना चाहते हैं)। –

उत्तर

6

संलयन एक दृष्टिकोण है, लेकिन क्यों

यानी

struct generic 
{ 
std::map<std::string, boost::variant<foo, bar, bob, int, double> > _impl; 
}; 

एक std::map एक std::string, जहां पेलोड boost::variant है द्वारा keyed में अपने "फील्ड" की दुकान नहीं ... और फिर आप कर सकते हैं बस अपने गेटर/सेटर में कुंजी को देखो ...

हेक, variant को optional में लपेटें और आपके पास वैकल्पिक फ़ील्ड हो सकते हैं!

एक अधिक जटिल उदाहरण:

class foo 
{ 
public: 
    typedef boost::variant<int, double, float, string> f_t; 
    typedef boost::optional<f_t&> return_value; 
    typedef map<string, return_value> ref_map_t; 

    foo() : f1(int()), f2(double()), f3(float()), f4(string()), f5(int()) 
    { 
    // save the references.. 
    _refs["f1"] = return_value(f1); 
    _refs["f2"] = return_value(f2); 
    _refs["f3"] = return_value(f3); 
    _refs["f4"] = return_value(f4); 
    _refs["f5"] = return_value(f5); 
    } 

    int getf1() const { return boost::get<int>(f1); } 
    double getf2() const { return boost::get<double>(f2); } 
    float getf3() const { return boost::get<float>(f3); } 
    string const& getf4() const { return boost::get<string>(f4); } 
    int getf5() const { return boost::get<int>(f5); } 

    // and setters.. 
    void setf1(int v) { f1 = v; } 
    void setf2(double v) { f2 = v; } 
    void setf3(float v) { f3 = v; } 
    void setf4(std::string const& v) { f4 = v; } 
    void setf5(int v) { f5 = v; } 

    // key based 
    return_value get(string const& key) 
    { 
    ref_map_t::iterator it = _refs.find(key); 
    if (it != _refs.end()) 
     return it->second; 
    return return_value(); 
    } 

    template <typename VT> 
    void set(string const& key, VT const& v) 
    { 
    ref_map_t::iterator it = _refs.find(key); 
    if (it != _refs.end()) 
     *(it->second) = v; 
    } 

private: 
    f_t f1; 
    f_t f2; 
    f_t f3; 
    f_t f4; 
    f_t f5; 

    ref_map_t _refs; 
}; 

int main(void) 
{ 
    foo fancy; 
    fancy.setf1(1); 
    cout << "f1: " << fancy.getf1() << endl; 

    fancy.set("f1", 10); 
    cout << "f1: " << fancy.getf1() << endl; 

    return 0; 
} 
+0

यह काम करेगा, लेकिन मैं सख्त प्रकार की जांच करना पसंद करता हूं, और मामलों में तेज़ रनटाइम एक्सेस पसंद करता हूं जब मुझे संकलन समय पर फ़ील्ड नाम पता होता है। –

+0

ठीक है, उस स्थिति में वास्तविक फ़ील्ड के मानचित्र संदर्भों में स्टोर (जो कि प्रकार के प्रकार हैं - ऊपर उदाहरण) ... – Nim

+0

यहां समस्या यह है कि 5 स्थान हैं जहां मुझे एक नया क्षेत्र जोड़ने की आवश्यकता है। यह जोड़ने के लिए बहुत सारे बॉयलरप्लेट की तरह लगता है जिसमें केवल संकलन-समय का नाम, एक स्ट्रिंग और प्रकार शामिल है। हो सकता है कि मैं फ़ील्ड को सार्वजनिक (और उनके गैर-प्रकार के प्रकार के साथ) करके अपने समाधान को संशोधित कर सकता हूं, और मानचित्र में संग्रहीत कुछ प्रकार के रैपर जो प्रत्येक को एक संस्करण से परिवर्तित करते हैं। –

1

आप C++ जो मुझे लगता है कि उपलब्ध नहीं है Reflection के लिए पूछ रहे हैं। आपको अपने कुछ के साथ आना होगा।

+0

आरटीटीआई सी ++ में उपलब्ध है, आप * प्रतिबिंब * के बारे में सोच रहे हैं ... :) – Nim

+0

हां, सी ++ में प्रतिबिंब इसे अधिक सरल बना देगा। मैं ऐसे समाधान के लिए बसूंगा जिसके लिए एक नया क्षेत्र जोड़ने के लिए कोड की न्यूनतम नई लाइनों की आवश्यकता होती है। –

+0

हाँ, आप सही हैं। अद्यतन उत्तर – Aamir

1

मैं इस के लिए क्या किया था एक बढ़ावा :: विपक्ष की तरह टाइप-सूची है कि मेरे सदस्यों और विवरण के कुछ प्रकार शामिल किया गया था। इसके बाद मैं अपने सदस्यों को "जंजीर" फ़ंक्शन कॉल द्वारा "मेटा-सूचना" डेटा संरचना में लगातार जोड़कर इस मानचित्रण का निर्माण करता हूं। बूस्ट.python में एक वर्ग को परिभाषित करने के लिए पूरी चीज बहुत समान दिखती है। यदि आप वास्तव में boost :: cons का उपयोग करते हैं, तो इसे boost.fusion में अनुक्रम के रूप में भी काम करना चाहिए, ताकि आप अपने डेटा पर अच्छी तरह से पुन: सक्रिय हो सकें। हो सकता है कि आप रन-टाइम पर लॉग (एन) एक्सेस समय प्राप्त करने के बजाय बूस्ट.फ्यूजन मानचित्र का उपयोग कर सकें, लेकिन ऐसा लगता है कि उनका आकार सीमित है जब तक कि विविध टेम्पलेट उपलब्ध न हों।

+0

मुझे लगता है कि दोनों बूस्ट :: फ़्यूज़न :: मानचित्र और बूस्ट :: विपक्ष में ओ (1) रन-टाइम एक्सेस है। –

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