2010-12-02 27 views
6

C++ uygulamasında üyelerine dinamik olarak erişime izin verecek bir yapının (veya benzer bir şeyin) olmasını isterim. Üyenin adını bir dize olarak alan ve bir çeşit varyant türü (ör. boost::variant) döndüren genel bir alıcı ve ayarlayıcıları olmalıdır.C++ yapısındaki üyelere hem dinamik hem de statik olarak erişme

boost::fusion::map kullanarak, her üyenin adını temsil eden bir dizeyi ekleyerek ve dizeler ile alıcı veya ayarlayıcı işlevleri arasında bir STL haritası oluşturarak gerçekleştirilebileceğini düşünüyordum. Tekerleği yeniden icat etmek istemiyorum, bu yüzden zaten var olan benzer bir şeyi umuyorum.

Ne düşünüyorsunuz? Benim fikrim işe yarar mı? Amacımı gerçekleştirmenin başka yollarını biliyor musun?

sayesinde Haggai

+2

Neden bunu istiyorsun? Doğrudan bunu destekleyen dillerde bile, yansıma, kötü kodun etrafından dolaşmak veya tembel programcılar için ucuz kod almak için kullanılan bir saldırıdır. –

+0

C++ size tip güvenliğini yeniliyor. Dünyada ne belirsizlik elde etmek için dağınık bir hack ile doğruluk için böyle basit, güçlü bir araç alışverişi haklı olabilir? – wilhelmtell

+0

@wilhelmtell: Doğru dengeyi bulmaya çalışıyorum. Çok belirsiz bir kaynaktan değerler okuyorum ve bunların genel bir şekilde çözümlenmesi ve ele alınması gerekiyor. Sadece küçük bir kısmı için doğru tipi biliyorum (ve bilmek istiyorum). –

cevap

6

füzyon bir yaklaşımdır, ama sonra ... yük boost::variant bir std::string, anahtarlı bir std::map içinde

yani

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

senin "alanları" depolayabilir ve neden yapabilirsiniz Sadece alıcı/ayarlayıcıdaki anahtarı arayın ...

heck, 'u bir optional içinde sarın ve isteğe bağlı alanlara sahip olabilirsiniz!

daha karmaşık bir örnek:

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

Bu işe yarar, ancak derleme zamanında alan adını bildiğim durumlarda sıkı tip denetimi ve daha hızlı çalışma zamanı erişimini tercih ederim. –

+0

tamam, bu durumda haritadaki gerçek alanlara yapılan referanslar (tip varyantı - yukarıdaki örnek) ... – Nim

+0

Burada sorun, yeni bir alan eklemem gereken 5 yer var. Bu, yalnızca bir derleme zamanı adı, bir dize ve türden neyin eklendiğine dair pek çok klişe gibi görünüyor. Belki de, alanlarınızı herkese açık (ve varyant olmayan türüyle) alarak ve her bir türe ve bir türe dönüştüren bir çeşit sarmalayıcılarla depolayarak çözümünüzü değiştirebilirim. –

1

Ne kullanılamaz düşündüğümüz C++ Reflection için soruyorsunuz. Kendi başına bir şey bulmalısın.

+0

RTTI C++ 'da mevcuttur, * sizce yansıma * ... :) – Nim

+0

Evet, C++' daki yansıma onu çok daha kolaylaştıracaktır. Yeni bir alan eklemek için en az yeni kod satırı gerektiren bir çözüm bulacağım. –

+0

Evet, haklısınız. Güncelleme yanıtı. – Aamir

1

Bunun için yaptıkların benim üyelerini ve açıklama çeşit içeren bir boost :: eksileri benzeri tip liste oldu. Ardından, üyelerimi "zincirleme" işlev çağrılarıyla "meta-bilgi" veri yapısına art arda ekleyerek bu eşleştirmeyi yapıyorum. Her şey, boost.python'da bir sınıfı tanımlamaya çok benziyor. Aslında, boost :: eksilerini kullanırsanız, boost.fusion'da bir dizi olarak da çalışmalıdır, böylece verileriniz üzerinde güzel bir şekilde yineleyebilirsiniz. Belki de çalışma zamanında log (n) erişim zamanları elde etmek için bir boost.fusion haritası kullanabilirsiniz, ancak variadic şablonlar kullanılabilir hale gelene kadar boyutları sınırlıdır.

+0

Sanırım her ikiside boost :: fusion :: map and boost :: cons O (1) run-time access var. –

İlgili konular