Bir C ++ uygulamasına nasıl yansıma ekleyebilirim?


263

Adı, içeriği (yani üyeler ve türleri) vb. İçin bir C ++ sınıfı introspect edebilmek istiyorum. Ben burada yansıması olan C ++ yönetilen değil, yerel C ++ konuşuyorum. C ++ RTTI kullanarak bazı sınırlı bilgi sağlar farkındayız. Hangi ek kütüphaneler (veya diğer teknikler) bu bilgiyi sağlayabilir?


18
Zor şanslar, makro ve diğer önişlemler olmadan yapamazsınız, çünkü bazı makro önişleme sihri ile manuel olarak oluşturmadıkça gerekli meta veriler mevcut değildir .
jalf

6
RTTI'dan geri alabileceğiniz bilgiler, aslında düşünmek istediğiniz şeylerin çoğunu yapmak için yeterli değildir. Örneğin bir sınıfın üye işlevleri üzerinde yineleme yapamazsınız.
Joseph Garvin

Yanıtlar:


259

Yapmanız gereken, önişlemcinin alanlar hakkında yansıma verileri üretmesidir. Bu veriler iç içe sınıflar olarak saklanabilir.

İlk olarak, önişlemciye yazmayı daha kolay ve daha temiz hale getirmek için yazılı ifadeyi kullanacağız. Yazılan ifade yalnızca türü parantez içine alan bir ifadedir. Yani int xyazmak yerine yazacaksınız (int) x. Yazılan ifadelere yardımcı olacak bazı kullanışlı makrolar:

#define REM(...) __VA_ARGS__
#define EAT(...)

// Retrieve the type
#define TYPEOF(x) DETAIL_TYPEOF(DETAIL_TYPEOF_PROBE x,)
#define DETAIL_TYPEOF(...) DETAIL_TYPEOF_HEAD(__VA_ARGS__)
#define DETAIL_TYPEOF_HEAD(x, ...) REM x
#define DETAIL_TYPEOF_PROBE(...) (__VA_ARGS__),
// Strip off the type
#define STRIP(x) EAT x
// Show the type without parenthesis
#define PAIR(x) REM x

Daha sonra, REFLECTABLEher alanla (artı alanın kendisi) ilgili verileri üretmek için bir makro tanımlarız . Bu makro şu şekilde adlandırılacaktır:

REFLECTABLE
(
    (const char *) name,
    (int) age
)

Boost.PP'yi kullanarak her bir argümanın üzerinde tekrarlıyoruz ve bu şekilde veri üretiyoruz:

// A helper metafunction for adding const to a type
template<class M, class T>
struct make_const
{
    typedef T type;
};

template<class M, class T>
struct make_const<const M, T>
{
    typedef typename boost::add_const<T>::type type;
};


#define REFLECTABLE(...) \
static const int fields_n = BOOST_PP_VARIADIC_SIZE(__VA_ARGS__); \
friend struct reflector; \
template<int N, class Self> \
struct field_data {}; \
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_EACH, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))

#define REFLECT_EACH(r, data, i, x) \
PAIR(x); \
template<class Self> \
struct field_data<i, Self> \
{ \
    Self & self; \
    field_data(Self & self) : self(self) {} \
    \
    typename make_const<Self, TYPEOF(x)>::type & get() \
    { \
        return self.STRIP(x); \
    }\
    typename boost::add_const<TYPEOF(x)>::type & get() const \
    { \
        return self.STRIP(x); \
    }\
    const char * name() const \
    {\
        return BOOST_PP_STRINGIZE(STRIP(x)); \
    } \
}; \

Bunun yaptığı, fields_nsınıftaki yansıtılabilir alanların sayısı olan bir sabit oluşturmaktır . Sonra field_dataher alan için uzmanlaşmıştır . Ayrıca reflectorsınıfı arkadaş , bu da özel olsa bile alanlara erişebilmesi için:

struct reflector
{
    //Get field_data at index N
    template<int N, class T>
    static typename T::template field_data<N, T> get_field_data(T& x)
    {
        return typename T::template field_data<N, T>(x);
    }

    // Get the number of fields
    template<class T>
    struct fields
    {
        static const int n = T::fields_n;
    };
};

Şimdi alanları yinelemek için ziyaretçi modelini kullanıyoruz. 0 ile alan sayısı arasında bir MPL aralığı oluştururuz ve bu dizindeki alan verilerine erişiriz. Ardından alan verilerini kullanıcı tarafından sağlanan ziyaretçiye aktarır:

struct field_visitor
{
    template<class C, class Visitor, class I>
    void operator()(C& c, Visitor v, I)
    {
        v(reflector::get_field_data<I::value>(c));
    }
};


template<class C, class Visitor>
void visit_each(C & c, Visitor v)
{
    typedef boost::mpl::range_c<int,0,reflector::fields<C>::n> range;
    boost::mpl::for_each<range>(boost::bind<void>(field_visitor(), boost::ref(c), v, _1));
}

Şimdi gerçek an için hepsini bir araya getirdik. Yansıtılabilir bir Personsınıfı şu şekilde tanımlayabiliriz :

struct Person
{
    Person(const char *name, int age)
        :
        name(name),
        age(age)
    {
    }
private:
    REFLECTABLE
    (
        (const char *) name,
        (int) age
    )
};

print_fieldsAlanlar üzerinde yineleme yapmak için yansıma verilerini kullanan genelleştirilmiş bir işlev şunlardır:

struct print_visitor
{
    template<class FieldData>
    void operator()(FieldData f)
    {
        std::cout << f.name() << "=" << f.get() << std::endl;
    }
};

template<class T>
void print_fields(T & x)
{
    visit_each(x, print_visitor());
}

print_fieldsYansıtılabilir Personsınıfla birlikte kullanımına bir örnek :

int main()
{
    Person p("Tom", 82);
    print_fields(p);
    return 0;
}

Hangi çıktılar:

name=Tom
age=82

Ve işte, C ++ 'da 100 kodun altında yansıma uyguladık.


106
Yansımanın nasıl yapılacağını göstermek için şeref, bunun yapılamayacağını söylemek yerine. SO'yı harika bir kaynak yapan bunun gibi cevaplar.
fearless_fool

4
Bunu Visual Studio altında derlemeye çalışırsanız, VS varyasyon makro genişletmesini düzgün işlemediği için bir hata alırsınız unutmayın. VS için şunu eklemeyi deneyin: #define DETAIL_TYPEOF_INT2(tuple) DETAIL_TYPEOF_HEAD tupleve #define DETAIL_TYPEOF_INT(...) DETAIL_TYPEOF_INT2((__VA_ARGS__)) TYPEOF (x) tanımını şu şekilde değiştirin:#define TYPEOF(x) DETAIL_TYPEOF_INT(DETAIL_TYPEOF_PROBE x,)
Phenglei Kai

'BOOST_PP_IIF_0' hatası alıyorum bir tür adı yok. Lütfen yardım edebilir misin.
Ankit Zalani

3
Kendi cevabımı gör - stackoverflow.com/a/28399807/2338477 Tüm tanımları çıkardım ve yeniden paketledim ve kitaplığı artırmaya gerek yok. Demo kodu olarak xml'ye serileştirme ve xml'den geri yükleme yapıyorum.
TarmoPikaro

106

Etrafta iki çeşit reflectionyüzme var.

  1. Bir türün üyeleri üzerinde yineleme yaparak, yöntemlerini numaralandırarak vb.

    Bu C ++ ile mümkün değildir.
  2. Sınıf türünün (sınıf, yapı, birleşim) bir yöntemi veya iç içe türü olup olmadığını kontrol ederek denetim, başka bir özel türden türetilir.

    Bu tür şeyler C ++ kullanarak mümkündür template-tricks. boost::type_traitsBirçok şey için kullanın (bir türün integral olup olmadığını kontrol etmek gibi). Üye işlevinin varlığını denetlemek için şunu kullanın : Bir işlevin varlığını denetlemek için bir şablon yazmak mümkün mü? . Belirli bir yuvalanmış türün olup olmadığını kontrol etmek için düz SFINAE kullanın .

Oldukça yerine 1) başarmak için yollar arıyorsanız, bir sınıfın kaç yöntem var gibi veya bir sınıf kimliğinin dize temsilini almak gibi, o zaman bunu yapmak için standart C ++ yolu yoktur korkarım. İkisini de kullanmalısın

  • Ek meta bilgileri ekleyerek kodunuzu çeviren Qt Meta Nesne Derleyicisi gibi bir Meta Derleyici.
  • Gerekli meta bilgileri eklemenize izin veren makrolardan oluşan bir Çerçeve. Çerçeveye tüm yöntemleri, sınıf adlarını, temel sınıfları ve ihtiyaç duyduğu her şeyi anlatmanız gerekir.

C ++ hız göz önünde bulundurularak yapılır. C # veya Java gibi üst düzey denetim istiyorsanız, o zaman korkarım size biraz çaba harcamadan bir yol olmadığını söylemeliyim.


122
C ++ hız göz önünde bulundurularak yapılır, ancak felsefe "mümkün olduğunca hızlı" değildir, bunun yerine "kullanmazsanız bunun bedelini ödemezsiniz." Bir dilin içgözlemi bu felsefeye uygun bir şekilde uygulamasının mümkün olduğuna inanıyorum, C ++ sadece eksik.
Joseph Garvin

8
@Joseph: Bu nasıl yapılmalı? Tüm bu meta verilerin depolanmasını gerektirir. Bu, kullanmasanız bile bunun bedelini ödemeniz gerektiği anlamına gelir. (Tek tek türleri "destekleyici yansıma" olarak işaretleyemezseniz, ancak mevcut makro hileyi de kullanabileceğimiz neredeyse aşağıdayız.
jalf

25
@jalf: Yalnızca ihtiyaç duyulabilecek meta veriler. Sadece derleme zamanı yansımasını düşünürsek, bu önemsizdir. Örneğin members<T>, T'nin tüm üyelerinin bir listesini döndüren bir derleme zamanı işlevi. Çalışma zamanı yansıması (yani yansımayla karıştırılmış RTTI) isteseydik, derleyici hala yansıyan taban türlerini bilirdi. Muhtemelen members<T>(T&)T = std :: string için somutlaştırılmayacaktır, bu nedenle std :: string veya türetilmiş sınıfları için RTTI'nın dahil edilmesi gerekmez.
MSalters

9
Refleks kütüphanesi (aşağıda belirtilmiştir) mevcut kodu yavaşlatmadan C ++ 'a yansıma ekler: root.cern.ch/drupal/content/reflex
Joseph Lisee

6
@Joe: Yansıma hiçbir zaman mevcut kodu yavaşlatmaz. Sadece teslim edilen şeyleri büyütür (bir tür bilgi veri tabanı teslim etmeniz gerektiğinden ...).
mmmmmmmm

56

Ve ben bir midilli isterdim, ama midilli özgür değil. :-p

http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI alacağınız şeydir. Düşündüğünüz gibi düşünme - çalışma zamanında tamamen açıklayıcı meta veriler - varsayılan olarak C ++ için mevcut değildir.


1
Ben ikinci Brad. C ++ şablonları oldukça güçlü olabilir ve çeşitli 'yansıma' tipi davranışlar etrafında zengin bir deneyim zenginliği vardır, örneğin 'herhangi bir' kütüphane, tür özellikleri, C ++ RTTI vb. Nick, buradaki amacın ne?
Aaron

7
Midilli sözleri için oy verin! Cevabınız da hak ettiği için iki kez oy verdim, ama ne yazık ki sadece bir tane aldım, bu yüzden midilli kazanıyor. :-)
Franci Penov

6
Bunun neden zekice bir yanıt olduğunu anlamıyorum. Bunu uygulamak için kütüphanelere vb. Başvurmak istediğimi zaten söyledim. Yansıtma / içgözlem komut dosyası erişimi, serileştirme vb. Çeşitli sistemlere yöneliktir
Nick

3
@ Nick: Bunu zaten yanıtladı. Bu yapılamaz, veriler mevcut değildir ve bu nedenle hiçbir kütüphane bunu sizin için uygulayamaz.
jalf

@jalf Programlama dünyasındaki insanları 'bunun mümkün değil' ve 'nasıl olduğunu bilmiyorum' gibi düşünerek okumak benim için hala garip. Elbette meta veriler mevcut değil ancak makrolarla eklenebilir
Freddx L.

38

Bilgiler var - ancak ihtiyacınız olan formatta değil, sadece sınıflarınızı dışa aktarıyorsanız. Bu Windows'da çalışıyor, diğer platformlar hakkında bilmiyorum. Depolama sınıfı belirticilerini aşağıdaki gibi kullanma:

class __declspec(export) MyClass
{
public:
    void Foo(float x);
}

Bu derleyicinin sınıf tanımı verilerini DLL / Exe'ye dönüştürmesini sağlar. Ancak, yansıma için kolayca kullanabileceğiniz bir biçimde değildir.

Şirketimde, bu meta verileri yorumlayan ve sınıfın kendisine fazladan makro vb. Eklemeden bir sınıfı yansıtmanıza izin veren bir kütüphane oluşturduk. Fonksiyonların aşağıdaki şekilde çağrılmasını sağlar:

MyClass *instance_ptr=new MyClass;
GetClass("MyClass")->GetFunction("Foo")->Invoke(instance_ptr,1.331);

Bu etkili bir şekilde şunları yapar:

instance_ptr->Foo(1.331);

Çağırma (this_pointer, ...) işlevinin değişken bağımsız değişkenleri vardır. Açıkçası, bir işlevi bu şekilde çağırarak, güvenlik ve benzeri şeyleri atlatıyorsunuz, bu nedenle bu yönler çalışma zamanı denetimleri olarak uygulanır.

Sözdiziminin geliştirilebileceğinden eminim ve şimdiye kadar sadece Win32 ve Win64 üzerinde çalışıyor. Sınıflara otomatik GUI arayüzlerine sahip olmak, C ++ 'da özellikler oluşturmak, XML'e ve XML'den vb. Akış yapmak için gerçekten yararlı bulduk ve belirli bir temel sınıftan türetmeye gerek yok. Yeterli talep varsa, serbest bırakılması için şekle sokabiliriz.


1
Sanırım demek __declspec(dllexport)ve bu tür oluşturma sırasında etkinleştirmeyi etkinleştirirseniz bir .map dosyasından bilgi alabilirsiniz.
Orwellophile

18

Yansıma, kutunun dışında C ++ tarafından desteklenmez. Bu üzücü çünkü savunma testlerini bir acı haline getiriyor.

Yansıma yapmak için birkaç yaklaşım vardır:

  1. hata ayıklama bilgilerini kullanın (taşınabilir olmayan).
  2. Kodunuzu makro / şablonlar veya başka bir kaynak yaklaşımla serpin (çirkin görünüyor)
  3. Veritabanı oluşturmak için clang / gcc gibi bir derleyiciyi değiştirin.
  4. Qt moc yaklaşımını kullan
  5. Yansımayı Artır
  6. Hassas ve Düz Yansıma

İlk bağlantı en umut verici görünüyor (klang için modları kullanır), ikincisi bir takım teknikleri tartışır, üçüncüsü gcc kullanan farklı bir yaklaşımdır:

  1. http://www.donw.org/rfl/

  2. https://bitbucket.org/dwilliamson/clreflect

  3. https://root.cern.ch/how/how-use-reflex

Şimdi C ++ yansıması için bir çalışma grubu var. C ++ 14 @ CERN ile ilgili haberlere bakın:

Düzenleme 13/08/17:

Orijinal görevden bu yana, yansıma üzerinde bir dizi potansiyel ilerleme olmuştur. Aşağıda çeşitli teknikler ve durum hakkında daha fazla ayrıntı ve tartışma sunulmaktadır:

  1. Kısaca Statik Yansıma
  2. Statik Yansıma
  3. Statik yansıma için bir tasarım

Bununla birlikte, C ++ 'da yansımayı destekleyen topluluktan daha fazla ilgi olmadıkça, yakın gelecekte C ++' da standartlaştırılmış bir yansımalar yaklaşımı için umut verici görünmemektedir.

Aşağıda, son C ++ standartları toplantısından alınan geri bildirimlere dayalı olarak geçerli durum ayrıntılı olarak açıklanmaktadır:

Düzenle 13/12/2017

Yansıma, C ++ 20 veya daha büyük olasılıkla bir TSR'ye doğru ilerliyor gibi görünüyor. Ancak hareket yavaştır.

Düzenle 15/09/2018

Oy pusulası için ulusal organlara bir taslak TS gönderildi.

Metin burada bulunabilir: https://github.com/cplusplus/reflection-ts

Düzenle 11/07/2019

Yansıma TS özelliği tamamlandı ve yaz (2019) için yorum ve oylama için dışarı.

Meta-şablon programlama yaklaşımı daha basit bir derleme zaman kodu yaklaşımıyla değiştirilmelidir (TS'ye yansıtılmaz).

Düzenle 10/02/2020

Visual Studio'da TS yansımasını desteklemek için bir istek var:

Yazar David Sankel'in TS hakkında konuşması:

Düzenle 17 Mart 2020

Yansıma konusunda ilerleme kaydedilmektedir. '2020-02 Prag ISO C ++ Komite Gezisi Raporu'ndan bir rapor burada bulunabilir:

C ++ 23 için neyin dikkate alındığıyla ilgili ayrıntılar burada bulunabilir (Yansıma hakkında kısa bölüm içerir):

Düzenle 4 Haziran 2020

Jeff Preshing tarafından çalışma zamanı yansıması için bir mekanizma içeren 'Plywood' adında yeni bir çerçeve yayınlandı. Daha fazla ayrıntıyı burada bulabilirsiniz:

Araçlar ve yaklaşım şimdiye kadar kullanımı en parlak ve en kolay gibi görünüyor.


1
Çekirdek bağlantısı kopuk.
Mostowski Çöküşü

cern bağlantıları şimdi düzeltilmelidir. Oldukça sık kırılma eğilimindedirler, bu da bir acıdır.
Damian Dixon

Bu cevap sadece derleme zamanı yansımasını mı dikkate alıyor?
einpoklum

@einpoklum yansıma için tek geçerli çözümler derleme zamanıdır, genellikle meta-şablon kodu veya makro ile. En son taslak TS, çalışma zamanı için çalışması gerektiği gibi görünüyor, ancak gerekli meta verilerin depolanması için tüm kitaplıkları doğru derleyiciyle oluşturmuş olmanız gerekir.
Damian Dixon

@DamianDixon: Bu doğru değil. Birkaç çalışma zamanı yansıma kütüphanesi vardır. Şimdi, oldukça karmaşıktırlar ve ya katılmaya ya da derleyici nodifikasyonlarına ihtiyaç duyarlar, ancak hala mevcutturlar. Yorumunuzu anladığım gibi, yalnızca derleme zamanı yansımasına başvurduysanız, daha net hale getirmek için lütfen yanıtınızı düzenleyin.
einpoklum

15

Ne yapmaya çalıştığınıza ve RTTI'nin gereksinimlerinizi karşılayıp karşılamayacağına bakmanız gerekir. Bazı özel amaçlar için kendi yalancı yansımamı uyguladım. Örneğin, bir keresinde bir simülasyonun çıktısını esnek bir şekilde yapılandırabilmek istedim. Çıktı alınacak sınıflara bazı kaynak kodu eklenmesi gerekiyordu:

namespace {
  static bool b2 = Filter::Filterable<const MyObj>::Register("MyObject");
} 

bool MyObj::BuildMap()
{
  Filterable<const OutputDisease>::AddAccess("time", &MyObj::time);
  Filterable<const OutputDisease>::AddAccess("person", &MyObj::id);
  return true;
}

İlk çağrı, bu nesneyi, hangi BuildMap()yöntemlerin kullanılabilir olduğunu bulmak için yöntemi çağıran filtreleme sistemine ekler .

Ardından, yapılandırma dosyasında şöyle bir şey yapabilirsiniz:

FILTER-OUTPUT-OBJECT   MyObject
FILTER-OUTPUT-FILENAME file.txt
FILTER-CLAUSE-1        person == 1773
FILTER-CLAUSE-2        time > 2000

Bazı şablon sihirleri sayesinde boostbu, çalışma zamanında (config dosyası okunduğunda) bir dizi yöntem çağrısına çevrilir, bu yüzden oldukça verimlidir. Gerçekten gerekmedikçe bunu yapmanızı tavsiye etmem, ancak bunu yaptığınızda gerçekten harika şeyler yapabilirsiniz.


Her zaman doğru olan bu işlevleri sevmeliyim;) Bunun statik başlatma sırası sorunlarından muaf olduğunu varsayıyorum?
paulm

14

Qt kullanmanızı tavsiye ederim .

Açık kaynaklı bir lisans ve ticari bir lisans vardır.


1
Ben buna baktım ama makrolar kullanır ve kaynak kodu meta-veri kodu oluşturmak için ayrıştırma gerekiyor. Bu ekstra adımdan kaçınmak istiyorum. Bir C ++ kütüphanesi veya basit makrolar kullanmayı tercih ederim. Yine de fikir için teşekkürler.
Nick

10
QT, ya da benzer bir yaklaşımı uygulayan başka bir kütüphane elde edeceğiniz en iyisidir
jalf

5
Derleme zamanında ödeme veya çalışma zamanında ödeme - her iki şekilde de ödeme yaparsınız!
Martin Beckett

13

Yansıtma ile ne yapmaya çalışıyorsunuz?
Sen Boost kullanabilirsiniz tip özellikleri ve typeof derleme zamanı yansıması sınırlı biçimi olarak kütüphaneler. Yani, bir şablona geçirilen bir türün temel özelliklerini inceleyebilir ve değiştirebilirsiniz.


13

DÜZENLEME : CAMP artık korunmamaktadır; iki çatal mevcuttur:

  • Bunlardan biri de CAMP olarak adlandırılır ve aynı API'yi temel alır.
  • Ponder kısmi bir yeniden yazmadır ve Boost gerektirmediği için tercih edilmelidir; C ++ 11 kullanıyor.

CAMP , C ++ diline yansıma ekleyen MIT lisanslı bir kütüphanedir (eski adıyla LGPL). Derlemede belirli bir önişleme adımı gerektirmez, ancak bağlamanın manuel olarak yapılması gerekir.

Geçerli Tegesoft kütüphanesi Boost kullanıyor, ancak C ++ 11 kullanan artık bir Boost gerektirmeyen bir çatal da var .


11

Bir zamanlar peşinde olduğunuz gibi bir şey yaptım ve bir miktar yansıma ve daha yüksek seviyeli özelliklere erişim sağlamak mümkün olsa da, bakım baş ağrısına değmeyebilir. Sistemim, Objective-C'nin iletme iletme ve iletme kavramına benzer şekilde temsilci seçme yoluyla kullanıcı arabirimi sınıflarını iş mantığından tamamen ayrı tutmak için kullanıldı. Bunu yapmanın yolu, işlev işaretleyicilerine (aslında değil) sembolleri eşleştirebilen bazı temel sınıflar oluşturmaktır (bir dize havuzu kullandım ancak hız ve derleme zamanı hata işlemeyi tercih ederseniz numaralandırmalarla yapabilirsiniz) saf işlev işaretçileri, ancak Boost'un Boost.Function ile sahip olduğu şeye benzer bir şey - ki o zaman erişemedim). Herhangi bir değeri temsil edebilecek bazı ortak taban sınıfınız olduğu sürece üye değişkenleriniz için de aynı işlemi yapabilirsiniz. Tüm sistem, Anahtar-Değer Kodlama ve Delegasyonunun el değmemiş bir ripoff'uydu, sistemi kullanan tüm sınıfları ve üyeleri yasal çağrılarla eşleştirmek için gerekli olan her sınıfı elde etmek için gerekli zamanın değerinde birkaç yan etki vardı. : 1) Herhangi bir sınıf, üstbilgi eklemek veya sahte taban sınıfları yazmak zorunda kalmadan başka bir sınıfta herhangi bir yöntemi çağırabilir, böylece arabirim derleyici için önceden tanımlanabilir; ve 2) Üye değişkenlerin alıcıları ve ayarlayıcıları, iş parçacıklarını güvenli hale getirmek kolaydır, çünkü değerlerini değiştirmek veya bunlara erişmek her zaman tüm nesnelerin temel sınıfındaki 2 yöntemle yapılır. Tüm sistem, Anahtar-Değer Kodlama ve Delegasyonunun el değmemiş bir ripoff'uydu, sistemi kullanan tüm sınıfları ve üyeleri yasal çağrılarla eşleştirmek için gerekli olan her sınıfı elde etmek için gerekli zamanın değerinde birkaç yan etki vardı. : 1) Herhangi bir sınıf, üstbilgi eklemek veya sahte taban sınıfları yazmak zorunda kalmadan başka bir sınıfta herhangi bir yöntemi çağırabilir, böylece arabirim derleyici için önceden tanımlanabilir; ve 2) Üye değişkenlerin alıcıları ve ayarlayıcıları, iş parçacıklarını güvenli hale getirmek kolaydır, çünkü değerlerini değiştirmek veya bunlara erişmek her zaman tüm nesnelerin temel sınıfındaki 2 yöntemle yapılır. Tüm sistem, Anahtar-Değer Kodlama ve Delegasyonunun el değmemiş bir ripoff'uydu, sistemi kullanan tüm sınıfları ve üyeleri yasal çağrılarla eşleştirmek için gerekli olan her sınıfı elde etmek için gerekli zamanın değerinde birkaç yan etki vardı. : 1) Herhangi bir sınıf, üstbilgi eklemek veya sahte taban sınıfları yazmak zorunda kalmadan başka bir sınıfta herhangi bir yöntemi çağırabilir, böylece arabirim derleyici için önceden tanımlanabilir; ve 2) Üye değişkenlerin alıcıları ve ayarlayıcıları, iş parçacıklarını güvenli hale getirmek kolaydır, çünkü değerlerini değiştirmek veya bunlara erişmek her zaman tüm nesnelerin temel sınıfındaki 2 yöntemle yapılır. 1) Herhangi bir sınıf, üstbilgileri eklemek veya sahte taban sınıfları yazmak zorunda kalmadan başka bir sınıftaki herhangi bir yöntemi çağırabilir, böylece arabirim derleyici için önceden tanımlanabilir; ve 2) Üye değişkenlerin alıcıları ve ayarlayıcıları, iş parçacıklarını güvenli hale getirmek kolaydır, çünkü değerlerini değiştirmek veya bunlara erişmek her zaman tüm nesnelerin temel sınıfındaki 2 yöntemle yapılır. 1) Herhangi bir sınıf, üstbilgileri eklemek veya sahte taban sınıfları yazmak zorunda kalmadan başka bir sınıftaki herhangi bir yöntemi çağırabilir, böylece arabirim derleyici için önceden tanımlanabilir; ve 2) Üye değişkenlerin alıcıları ve ayarlayıcıları, iş parçacıklarını güvenli hale getirmek kolaydır, çünkü değerlerini değiştirmek veya bunlara erişmek her zaman tüm nesnelerin temel sınıfındaki 2 yöntemle yapılır.

Ayrıca, aksi takdirde C ++ 'da kolay olmayan bazı gerçekten garip şeyler yapma olasılığına yol açtı. Örneğin, kendisi de dahil olmak üzere herhangi bir türden rasgele öğeler içeren bir Array nesnesi oluşturabilir ve tüm dizi öğelerine bir ileti geçirerek ve dönüş değerlerini (Lisp'teki haritaya benzer) toplayarak dinamik olarak yeni diziler oluşturabilirim. Bir diğeri, değeri sürekli sorgulamak veya gereksiz yere ekranı yeniden çizmek yerine UI'yi arka uç sınıflarının üyelerindeki değişikliklere hemen yanıt verecek şekilde ayarlayabildi.

Belki de sizin için daha ilginç olanı, bir sınıf için tanımlanan tüm yöntemleri ve üyeleri ve dize formunda daha az olmamaktır.

Sizi rahatsız etmenizi engelleyebilecek sistemin dezavantajları: tüm mesajları ve anahtar / değer çiftlerini eklemek son derece sıkıcıdır; herhangi bir yansıma olmadan daha yavaştır; görmekten nefret etmek için büyüyeceksin boost::static_pointer_castveboost::dynamic_pointer_castşiddetli bir tutku ile kod tabanınızın her yerinde ; kuvvetle yazılan sistemin sınırlamaları hala orada, gerçekten onları biraz saklıyorsunuz, bu yüzden açık değil. Dizelerinizdeki yazım hataları da eğlenceli veya keşfedilmesi kolay bir sürpriz değildir.

Böyle bir şeyi nasıl uygulayacağınıza gelince: sadece ortak bir tabana paylaşılan ve zayıf işaretçiler kullanın (benimkine çok yaratıcı bir şekilde "Nesne" denir) ve kullanmak istediğiniz tüm türler için türetin. İşlev işaretçisi aramalarını sarmak için bazı özel bok ve bir ton çirkin makro ile yaptığım gibi yapmak yerine Boost.Function yüklemenizi tavsiye ederim. Her şey eşlendiğinden, nesneleri incelemek sadece tüm anahtarları yineleme meselesidir. Sınıflarım aslında sadece C ++ kullanarak mümkün olduğunca doğrudan bir Cocoa ripoff yakın olduğu için, böyle bir şey istiyorsanız o zaman bir taslak olarak Cocoa belgelerini kullanmanızı öneririm.


Hey, @Michael; bunun için hala kaynak kodunuz var mı veya bundan kurtuldunuz mu? Eğer sakıncası yoksa göz atmak isterim.
RandomDSdevel

Hata! Adınızı yanlış yazdınız! Hiç cevap
alamadım

10

C ++ 'da RTTR (Çalışma Zamanı Türü Yansıması, ayrıca github ) adı verilen yeni bir kütüphane vardır .

Arayüz C # yansımasına benzer ve herhangi bir RTTI olmadan çalışır.


8

C ++ günlerimden bildiğim iki yansıma benzeri çözüm şunlardır:

1) Tüm sınıflarınızın bir 'nesne' temel sınıfından türetilmesini sağlayabiliyorsanız, yansıma benzeri davranışınızı geliştirmeniz için bir önyükleme sağlayacak RTTI kullanın. Bu sınıf, GetMethod, GetBaseClass vb. Gibi bazı yöntemler sağlayabilir. Bu yöntemlerin nasıl çalıştığı konusunda, türlerinizi süslemek için manuel olarak bazı makrolar eklemeniz gerekir; bu, sahnelerin arkasında GetMethods'a yanıt sağlamak için türde meta veri oluşturur.

2) Derleyici nesnelerine erişiminiz varsa, başka bir seçenek DIA SDK kullanmaktır . Doğru hatırlıyorsam, bu C ++ türleriniz için meta veriler içermesi gereken pdbs'yi açmanıza izin verir. İhtiyacınız olanı yapmak yeterli olabilir. Bu sayfa , örneğin bir sınıfın tüm temel türlerini nasıl alabileceğinizi gösterir.

Her iki çözüm de biraz çirkin! C # lükslerini takdir etmek için biraz C ++ gibi bir şey yoktur.

İyi şanslar.


Bu, sizin önerdiğiniz DIA SDK şeyiyle kurnaz ve dev bir hack.
Sqeaky

7

EDIT: 7 Şubat 2017 itibariyle kırık bağlantı güncellendi.

Bence kimse bundan bahsetmedi:

CERN'de C ++ için tam bir yansıma sistemi kullanırlar:

CERN Refleks . Çok iyi çalışıyor gibi görünüyor.


@ j4nbur53 Bağlantı koptu, çünkü bir dönüm noktasına ulaştılar: root.cern.ch
Germán Diago

Bu bağlantı demek istiyor olabilir misiniz root.cern.ch/root/doc/ROOTUsersGuideHTML/ch07.html Bölüm Refleks?
Mostowski Çöküşü

Bu root.cern.ch/how/how-use-reflex öğesini deneyin . Reflex, başlık dosyalarınızı ayrıştıran ve basit bir API'ye bağlayabileceğiniz ve kullanabileceğiniz c ++ introspection kodu / kitaplığı üreten bir jeneratör olarak çalışır.
Adam Ryczkowski

6

Bu soru şu anda biraz eski (neden bugün eski soruları vurmaya devam ettiğimi bilmiyorum) ama derleme zamanı yansıması getiren BOOST_FUSION_ADAPT_STRUCT hakkında düşünüyordum .

Bunu elbette çalışma zamanı yansımasıyla eşleştirmek size kalmış ve çok kolay olmayacak, ancak tersi olmasa da bu yönde mümkündür :)

Gerçekten bir kapsüllemek için bir makro BOOST_FUSION_ADAPT_STRUCTçalışma zamanı davranışı almak için gerekli yöntemleri üretebilir düşünüyorum .


2
minghua (gönderiyi ilk düzenleyen): Bu BOOST_FUSION_ADAPT_STRUCT çözümüne girdim ve sonunda bir örnek buldum. Bu yeni SO sorusuna bakın - C ++, boost fusion adap_struct ile iç içe yapı alanına yineleyin .
Matthieu M.

Harika Matthieu! Sadece geçen yıl boyunca burada ve orada ipuçlarını gördüklerini fark ettim. Şu ana kadar ilgili olduklarını fark etmediler. Bunlar çok ilham vericiydi.
minghua

6

Ben Dominic Filion tarafından "C ++ Yansıma Şablonları kullanma" makalesini ilginç bulabilirsiniz düşünüyorum. Oyun Programlama Taşları 5 bölüm 1.4 . Ne yazık ki yanımda bir kopyam yok, ama bak çünkü ne istediğini açıklıyor.


4

Ponder bu soruya cevap olarak bir C ++ yansıma kütüphanesidir. Seçenekleri düşündüm ve tüm kutularımı işaretleyen birini bulamadığım için kendim yapmaya karar verdim.

Bu soruya büyük cevaplar olmasına rağmen, tonlarca makro kullanmak veya Boost'a güvenmek istemiyorum. Boost harika bir kütüphane, ancak daha basit ve daha hızlı derleme sürelerine sahip birçok küçük ısmarlama C ++ 0x projesi var. C ++ 11'i desteklemeyen (henüz?) Bir C ++ kütüphanesini sarma gibi bir sınıfı harici olarak dekore edebilmenin avantajları da vardır. C ++ 11 kullanan CAMP çatalı, artık Boost gerektirmiyor .


4

Yansıtma, derleyicinin çalışma zamanı kodunun sorgulayabileceği kodda ayak izi olarak bırakmaya karar vermesiyle ilgilidir. C ++, kullanmadığınız şeyleri ödememekle ünlüdür; çünkü çoğu insan yansıma kullanmaz / istemez, C ++ derleyicisi hiçbir şey kaydetmeyerek maliyeti önler .

Yani, C ++ yansıma sağlamaz ve diğer cevapların belirttiği gibi, genel kural olarak kendiniz "simüle etmek" kolay değildir.

"Diğer teknikler" altında, yansımalı bir diliniz yoksa, derleme zamanında istediğiniz bilgileri elde edebileceğiniz bir araç edinin.

Bizim DMS Yazılım Değişim Mühendisliği Toolkit açık dildeki tanımları parametreli derleyici teknolojisi genelleştirilmiş edilir. C, C ++, Java, COBOL, PHP, için dil tanımları vardır ...

C, C ++, Java ve COBOL sürümleri için, ayrıştırma ağaçlarına ve sembol tablosu bilgilerine tam erişim sağlar. Bu sembol tablosu bilgileri, "yansıma" dan isteyebileceğiniz veri türlerini içerir. Eğer amaç alanları veya yöntemlerden bazıları kümesini sıralamak ve ise do onlarla bir şeyler, DMS sen keyfi şekillerde sembol tablolarında bulmak neye göre kod dönüştürmek için kullanılabilir.


3

Burada başka bir kütüphane bulabilirsiniz: http://www.garret.ru/cppreflection/docs/reflect.html 2 yolu destekler: hata ayıklama bilgilerinden tür bilgisi almak ve programcının bu bilgileri sağlamasına izin vermek.

Ayrıca projem için yansımayla ilgileniyorum ve bu kütüphaneyi buldum, henüz denemedim, ancak bu adamdan diğer araçları denedim ve nasıl çalıştıklarını beğendim :-)


3

Classdesc http://classdesc.sf.net adresine bakın . Sınıf "tanımlayıcıları" biçiminde yansıma sağlar, herhangi bir standart C ++ derleyicisiyle çalışır (evet, Visual Studio ve GCC ile çalıştığı bilinmektedir) ve kaynak kodu ek açıklama gerektirmez (ancak bazı zor durumları işlemek için bazı pragmalar var ). On yıldan fazla bir süredir geliştirilmekte ve bir dizi endüstriyel ölçekli projede kullanılmaktadır.


1
Stack Overflow'a hoş geldiniz. Bu cevap konuyla ilgili olmasına rağmen, bu yazılımın yazarı olduğunuzu belirtmek önemlidir, bunun tarafsız bir öneri olmadığını açıkça belirtmek için :-)
Matthew Strawbridge

2

C ++ 'da yansıma istediğimde okudum bu makaleyi ve orada gördüklerimi geliştirdim. Maalesef, kutu yok. Sonucun sahibiyim ... ama kesinlikle sahip olduğum şeyi alıp oradan gidebilirsin.

Şu anda, kendimi hissettiğimde, yansıtılabilir türlerin tanımını daha kolay hale getirmek için inherit_linearly kullanma yöntemlerini araştırıyorum. Aslında oldukça uzağa girdim ama hala gidecek bir yolum var. C ++ 0x'deki değişikliklerin bu alanda çok yardımcı olması muhtemeldir.


2

Görünüşe göre C ++ hala bu özelliğe sahip değil. Ve C ++ 11 yansımayı da erteledi ((

Bazı makroları arayın veya kendiniz yapın. Qt ayrıca yansımayla da yardımcı olabilir (eğer kullanılabilirse).


2

yansıma c ++ 'da kullanıma hazır olarak desteklenmese de, uygulanması çok zor değildir. Bu harika makaleyle karşılaştım: http://replicaisland.blogspot.co.il/2010/11/building-reflective-object-system-in-c.html

makalede oldukça basit ve ilkel bir yansıma sistemini nasıl uygulayabileceğiniz ayrıntılı olarak açıklanmaktadır. verilen en sağlıklı çözüm değil ve ayrılmak için pürüzlü kenarlar var ama benim ihtiyaçları için yeterli oldu.

alt satırda - yansıma doğru yapılırsa ödeyebilir ve c ++ 'da tamamen uygulanabilir.


2

Otomatik içgözlem / yansıma araç takımı "IDK" varlığını tanıtmak istiyorum. Qt gibi bir meta derleyici kullanır ve meta bilgileri doğrudan nesne dosyalarına ekler. Kullanımı kolay olduğu iddia ediliyor. Harici bağımlılık yok. Hatta std :: string'i otomatik olarak yansıtmanıza ve daha sonra komut dosyalarında kullanmanıza izin verir. Lütfen IDK'ya bakın


2

Eğer nispeten basit C ++ yansıması arıyorsanız - Ben çeşitli kaynaklardan makro / tanımlar topladı ve nasıl çalıştığını yorumladı. Başlık dosyalarını buradan indirebilirsiniz:

https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h

tanımlar kümesi ve üstündeki işlevsellik:

https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h https://github.com/tapika/TestCppReflect/blob/master/CppReflect.cpp https://github.com/tapika/TestCppReflect/ leke / ana / TypeTraits.h

Örnek uygulama git deposunda da bulunur: https://github.com/tapika/TestCppReflect/

Kısmen buraya açıklama ile kopyalayacağım:

#include "CppReflect.h"
using namespace std;


class Person
{
public:

    // Repack your code into REFLECTABLE macro, in (<C++ Type>) <Field name>
    // form , like this:

    REFLECTABLE( Person,
        (CString)   name,
        (int)       age,
...
    )
};

void main(void)
{
    Person p;
    p.name = L"Roger";
    p.age = 37;
...

    // And here you can convert your class contents into xml form:

    CStringW xml = ToXML( &p );
    CStringW errors;

    People ppl2;

    // And here you convert from xml back to class:

    FromXml( &ppl2, xml, errors );
    CStringA xml2 = ToXML( &ppl2 );
    printf( xml2 );

}

REFLECTABLEdefine, offsetofbelleğin belirli bir alanında hangi yerde bulunduğunu belirlemek için - ile sınıf adı + alan adını kullanır . Mümkün olduğunca .NET terminolojisi almaya çalıştım, ancak C ++ ve C # farklı, bu yüzden 1'e 1 değil. Bütün C ++ yansıma modeli içinde bulunur TypeInfove FieldInfosınıflar.

Demo kodu xml içine almak ve geri xml geri yüklemek için pugi xml ayrıştırıcı kullandım.

Demo kodu tarafından üretilen çıktı şuna benzer:

<?xml version="1.0" encoding="utf-8"?>
<People groupName="Group1">
    <people>
        <Person name="Roger" age="37" />
        <Person name="Alice" age="27" />
        <Person name="Cindy" age="17" />
    </people>
</People>

TypeTraits sınıfı ve kısmi şablon belirtimi aracılığıyla herhangi bir 3. taraf sınıf / yapı desteğini etkinleştirmek de mümkündür - kendi TypeTraitsT sınıfınızı CString veya int'e benzer şekilde tanımlamak için - bkz.

https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195

Bu çözüm Windows / Visual studio için geçerlidir. Diğer işletim sistemlerine / derleyicilere taşımak mümkündür, ancak bunu yapmadım. (Çözümü gerçekten beğenip beğenmediğinizi sorun, size yardımcı olabilirim)

Bu çözüm, birden fazla alt sınıf ile bir sınıfın tek seferlik serileştirmesi için geçerlidir.

Bununla birlikte, sınıf parçalarını serileştirmek veya yansıma çağrılarının hangi işlevsellik ürettiğini kontrol etmek için bir mekanizma arıyorsanız, aşağıdaki çözümü inceleyebilirsiniz:

https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel

Daha ayrıntılı bilgi youtube videosunda bulunabilir:

C ++ Çalışma Zamanı Türü Yansıması https://youtu.be/TN8tJijkeFE

C ++ yansıması nasıl çalışacağını biraz daha derin anlatmaya çalışıyorum.

Örnek kod aşağıdaki gibi görünecektir:

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp

c.General.IntDir = LR"(obj\$(ProjectName)_$(Configuration)_$(Platform)\)";
c.General.OutDir = LR"(bin\$(Configuration)_$(Platform)\)";
c.General.UseDebugLibraries = true;
c.General.LinkIncremental = true;
c.CCpp.Optimization = optimization_Disabled;
c.Linker.System.SubSystem = subsystem_Console;
c.Linker.Debugging.GenerateDebugInformation = debuginfo_true;

Ancak buradaki her adım aslında C ++ özellikleri ile işlev çağrısı ile sonuçlanır __declspec(property(get =, put ... ).

C ++ Veri Türleri, C ++ özellik adları ve sınıf örneği işaretçileri hakkında, yol biçiminde tam bilgi alan ve bu bilgilere dayanarak xml, json oluşturabilir ve hatta bunu internet üzerinden serileştirebilirsiniz.

Bu tür sanal geri arama işlevlerine örnekler burada bulunabilir:

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp

Bkz. Fonksiyonlar ReflectCopyve sanal fonksiyon ::OnAfterSetProperty.

Ancak konu gerçekten gelişmiş olduğu için - önce videoyu kontrol etmenizi öneririz.

Bazı iyileştirme fikirleriniz varsa, benimle iletişime geçmekten çekinmeyin.


1

C ++ 'da yansıma çok yararlıdır, her üye için bazı yöntemler çalıştırmanız gerekir (Örneğin: serileştirme, karma, karşılaştırma). Çok basit bir sözdizimi ile genel bir çözümle geldim:

struct S1
{
    ENUMERATE_MEMBERS(str,i);
    std::string str;
    int i;
};
struct S2
{
    ENUMERATE_MEMBERS(s1,i2);
    S1 s1;
    int i2;
};

ENUMERATE_MEMBERS, daha sonra açıklanacak bir makro olduğunda (UPDATE):

Diyelim ki int ve std :: string için serileştirme fonksiyonunu şu şekilde tanımladık:

void EnumerateWith(BinaryWriter & writer, int val)
{
    //store integer
    writer.WriteBuffer(&val, sizeof(int));
}
void EnumerateWith(BinaryWriter & writer, std::string val)
{
    //store string
    writer.WriteBuffer(val.c_str(), val.size());
}

Ve "gizli makro" yakınında genel fonksiyonumuz var;)

template<typename TWriter, typename T>
auto EnumerateWith(TWriter && writer, T && val) -> is_enumerable_t<T>
{
    val.EnumerateWith(write); //method generated by ENUMERATE_MEMBERS macro
}

Şimdi yazabilirsin

S1 s1;
S2 s2;
//....
BinaryWriter writer("serialized.bin");

EnumerateWith(writer, s1); //this will call EnumerateWith for all members of S1
EnumerateWith(writer, s2); //this will call EnumerateWith for all members of S2 and S2::s1 (recursively)

Yapı tanımında ENUMERATE_MEMBERS makrosuna sahip olduğunuzda, orijinal türe dokunmadan serileştirme, karşılaştırma, karma ve diğer öğeleri oluşturabilirsiniz, tek gereksinim, numaralandırılamayan her tür için (SayaryWriter gibi) her tür için "EnumerateWith" yöntemini uygulamaktır. . Genellikle projenizdeki herhangi bir türü desteklemek için 10-20 "basit" tip uygulamanız gerekir.

Bu makronun çalışma zamanında oluşturma / imha yapılandırması için sıfır ek yükü olmalıdır ve T.EnumerateWith () kodu isteğe bağlı olarak oluşturulmalıdır; bu da şablon satır içi işlevi yapılarak elde edilebilir, böylece tek ek yük tüm hikaye her yapıya ENUMERATE_MEMBERS (m1, m2, m3 ...) eklemek, üye türü başına belirli bir yöntem uygulamak ise herhangi bir çözüm bir zorunluluktur, bu yüzden onu yük olarak kabul etmiyoruz.

GÜNCELLEME: ENUMERATE_MEMBERS makrosunun çok basit bir uygulaması var (ancak numaralandırılabilir yapıdan miras alınmasını desteklemek için biraz genişletilebilir)

#define ENUMERATE_MEMBERS(...) \
template<typename TEnumerator> inline void EnumerateWith(TEnumerator & enumerator) const { EnumerateWithHelper(enumerator, __VA_ARGS__ ); }\
template<typename TEnumerator> inline void EnumerateWith(TEnumerator & enumerator) { EnumerateWithHelper(enumerator, __VA_ARGS__); }

// EnumerateWithHelper
template<typename TEnumerator, typename ...T> inline void EnumerateWithHelper(TEnumerator & enumerator, T &...v) 
{ 
    int x[] = { (EnumerateWith(enumerator, v), 1)... }; 
}

// Generic EnumerateWith
template<typename TEnumerator, typename T>
auto EnumerateWith(TEnumerator & enumerator, T & val) -> std::void_t<decltype(val.EnumerateWith(enumerator))>
{
    val.EnumerateWith(enumerator);
}

Ve bu 15 kod satırı için herhangi bir üçüncü taraf kütüphanesine ihtiyacınız yoktur;)


1

Boost :: Hana kütüphanesinden BOOST_HANA_DEFINE_STRUCT ile yapılar için harika statik yansıma özellikleri elde edebilirsiniz .
Hana oldukça çok yönlüdür, sadece aklınızdaki kullanım için değil, birçok şablon meta programlaması için de geçerlidir.


1

Rasgele Erişim Yansıma ya dizilerde bulunmayabilir veya dizi erişimi gibi hissetmeye için tüm alan / türü bilgileri tasarlanmıştır - kütüphanesi oldukça kolay ve sezgisel yansıma yapar. C ++ 17 için yazılmıştır ve Visual Studios, g ++ ve Clang ile çalışır. Kütüphane sadece başlıktır, yani onu kullanmak için projenize yalnızca "Reflect.h" kopyalamanız gerekir.

Yansıtılan yapılar veya sınıflar yansıttığınız sınıfın adını ve alanların adlarını verdiğiniz REFLECT makrosuna ihtiyaç duyar.

class FuelTank {
    public:
        float capacity;
        float currentLevel;
        float tickMarks[2];

    REFLECT(() FuelTank, () capacity, () currentLevel, () tickMarks)
};

Hepsi bu kadar, yansımayı ayarlamak için ek kod gerekmez. İsteğe bağlı olarak, üst sınıfları geçebilmek veya bir alana ek derleme zamanı bilgisi (Json gibi) ekleyebilmek için üst sınıflar (ilk bağımsız değişkenin parantezinde) ve alan ek açıklamaları (ek açıklama yapmak istediğiniz alanın önündeki parantez içinde) sağlayabilirsiniz. :Göz ardı etmek).

Alanlar arasında geçiş yapmak kadar basit olabilir ...

for ( size_t i=0; i<FuelTank::Class::TotalFields; i++ )
    std::cout << FuelTank::Class::Fields[i].name << std::endl;

Alan değerlerine (okuyabileceğiniz veya değiştirebileceğiniz) ve alan türü bilgilerine erişmek için bir nesne örneği arasında döngü yapabilirsiniz ...

FuelTank::Class::ForEachField(fuelTank, [&](auto & field, auto & value) {
    using Type = typename std::remove_reference<decltype(value)>::type;
    std::cout << TypeToStr<Type>() << " " << field.name << ": " << value << std::endl;
});

Bir JSON Kütüphanesi , okuma veya yazma için uygun JSON çıktı temsillerini otomatik olarak tanımlayan ve yansıtılan alanları, dizileri ve STL kaplarını tekrar tekrar geçebilen RandomAccessReflection üzerine kurulmuştur.

struct MyOtherObject { int myOtherInt; REFLECT(() MyOtherObject, () myOtherInt) };
struct MyObject
{
    int myInt;
    std::string myString;
    MyOtherObject myOtherObject;
    std::vector<int> myIntCollection;

    REFLECT(() MyObject, () myInt, () myString, (Reflected) myOtherObject, () myIntCollection)
};

int main()
{
    MyObject myObject = {};
    std::cout << "Enter MyObject:" << std::endl;
    std::cin >> Json::in(myObject);
    std::cout << std::endl << std::endl << "You entered:" << std::endl;
    std::cout << Json::pretty(myObject);
}

Yukarıdaki gibi çalıştırılabilir ...

Enter MyObject:
{
  "myInt": 1337, "myString": "stringy", "myIntCollection": [2,4,6],
  "myOtherObject": {
    "myOtherInt": 9001
  }
}


You entered:
{
  "myInt": 1337,
  "myString": "stringy",
  "myOtherObject": {
    "myOtherInt": 9001
  },
  "myIntCollection": [ 2, 4, 6 ]
}

Ayrıca bakınız...


0

Böyle bir işleve bir işaretçi bildirirseniz:

int (*func)(int a, int b);

Bu işleve bellekte böyle bir yer atayabilirsiniz ( libdlve gerektirir dlopen)

#include <dlfcn.h>

int main(void)
{
    void *handle;
    char *func_name = "bla_bla_bla";
    handle = dlopen("foo.so", RTLD_LAZY);
    *(void **)(&func) = dlsym(handle, func_name);
    return func(1,2);
}

Dolaylı olarak yerel bir sembol yüklemek dlopeniçin arama ikili dosyasında (argv[0] ) kullanabilirsiniz.

(Dışındaki Bunun için tek koşul dlopen(), libdlve dlfcn.hargümanları ve fonksiyon tipini bilmektir).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.