Chciałbym mieć możliwość introspekcji klasy C ++ pod kątem jej nazwy, zawartości (tj. Członków i ich typów) itp. Mówię tutaj o natywnym C ++, nie zarządzanym C ++, który ma odbicie. Zdaję sobie sprawę, że C ++ dostarcza pewne ograniczone informacje za pomocą RTTI. Jakie dodatkowe biblioteki (lub inne techniki) mogłyby dostarczyć te informacje?
c++
reflection
templates
sfinae
Nacięcie
źródło
źródło
Odpowiedzi:
To, co musisz zrobić, to, aby preprocesor wygenerował dane odbicia na temat pól. Te dane mogą być przechowywane jako zagnieżdżone klasy.
Po pierwsze, aby ułatwić i uprościć pisanie go w preprocesorze, użyjemy wyrażenia pisanego na maszynie. Wyrażenie na maszynie jest tylko wyrażeniem, które umieszcza typ w nawiasie. Zamiast pisać
int x
, napiszesz(int) x
. Oto kilka przydatnych makr pomocnych przy wpisywaniu wyrażeń:Następnie definiujemy
REFLECTABLE
makro do generowania danych o każdym polu (oraz o samym polu). To makro będzie się nazywać tak:Tak więc za pomocą Boost.PP iterujemy każdy argument i generujemy dane w następujący sposób:
Powoduje to wygenerowanie stałej,
fields_n
która jest liczbą pól odblaskowych w klasie. Następnie specjalizuje sięfield_data
w każdej dziedzinie. Zaprzyjaźnia się także zreflector
klasą, dzięki czemu ma dostęp do pól, nawet gdy są prywatne:Teraz do iteracji po polach używamy wzorca odwiedzającego. Tworzymy zakres MPL od 0 do liczby pól i uzyskujemy dostęp do danych pól pod tym indeksem. Następnie przekazuje dane pola odwiedzającemu użytkownika:
Teraz chwila prawdy zebraliśmy to wszystko. Oto, w jaki sposób możemy zdefiniować
Person
klasę, która jest odzwierciedlalna:Oto uogólniona
print_fields
funkcja wykorzystująca dane odbicia do iteracji po polach:Przykład użycia
print_fields
zPerson
klasą odblaskową :Które wyjścia:
I voila, właśnie wdrożyliśmy odbicie w C ++, w mniej niż 100 liniach kodu.
źródło
#define DETAIL_TYPEOF_INT2(tuple) DETAIL_TYPEOF_HEAD tuple
i#define DETAIL_TYPEOF_INT(...) DETAIL_TYPEOF_INT2((__VA_ARGS__))
zmień definicję TYPEOF (x) na:#define TYPEOF(x) DETAIL_TYPEOF_INT(DETAIL_TYPEOF_PROBE x,)
Istnieją dwa rodzaje
reflection
pływania.Nie jest to możliwe w C ++.
Tego rodzaju rzeczy są możliwe przy użyciu C ++
template-tricks
. Użyjboost::type_traits
do wielu rzeczy (takich jak sprawdzanie, czy typ jest całką). Aby sprawdzić istnienie funkcji składowej, użyj Czy można napisać szablon, aby sprawdzić istnienie funkcji? . Aby sprawdzić, czy istnieje pewien typ zagnieżdżony, użyj zwykłego SFINAE .Jeśli szukasz sposobów na osiągnięcie 1), na przykład sprawdzania, ile metod ma klasa, lub uzyskania reprezentacji ciągu identyfikatora klasy, obawiam się, że nie ma na to sposobu w Standard C ++. Musisz użyć albo
C ++ jest stworzony z myślą o szybkości. Jeśli chcesz inspekcji na wysokim poziomie, takiej jak C # lub Java, obawiam się, że muszę ci powiedzieć, że nie ma drogi bez wysiłku.
źródło
members<T>
która zwraca listę wszystkich członków T. Gdybyśmy chcieli mieć odbicie środowiska uruchomieniowego (tj. RTTI zmieszane z odbiciem), kompilator nadal zna wszystkie odbite typy bazowe. Jest całkiem prawdopodobne,members<T>(T&)
że nigdy nie zostanie utworzona instancja dla T = std :: string, więc RTTI dla std :: string lub jego pochodnych klas nie musi być uwzględnione.I chciałbym kucyka, ale kucyki nie są wolne. :-p
http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI jest tym, co dostaniesz. Refleksja, o której myślisz - w pełni opisowe metadane dostępne w czasie wykonywania - po prostu domyślnie nie istnieje dla C ++.
źródło
Informacje istnieją - ale nie w wymaganym formacie i tylko jeśli wyeksportujesz swoje klasy. Działa to w systemie Windows, nie wiem o innych platformach. Używanie specyfikatorów klasy pamięci jak na przykład:
To powoduje, że kompilator buduje dane definicji klasy w DLL / Exe. Ale nie jest w formacie, którego można łatwo użyć do refleksji.
W mojej firmie zbudowaliśmy bibliotekę, która interpretuje te metadane i umożliwia odzwierciedlenie klasy bez wstawiania dodatkowych makr itp. W samej klasie. Pozwala na wywoływanie funkcji w następujący sposób:
To skutecznie:
Funkcja Invoke (this_pointer, ...) ma zmienne argumenty. Oczywiście przez wywołanie funkcji w ten sposób omijasz rzeczy takie jak const-safety itp., Więc te aspekty są implementowane jako kontrole środowiska wykonawczego.
Jestem pewien, że składnię można poprawić, a do tej pory działa ona tylko w systemach Win32 i Win64. Przekonaliśmy się, że jest to bardzo przydatne do posiadania automatycznych interfejsów GUI do klas, tworzenia właściwości w C ++, przesyłania strumieniowego do i z XML itd. I nie ma potrzeby czerpania z konkretnej klasy bazowej. Jeśli jest wystarczający popyt, może uda nam się go ukształtować do wydania.
źródło
__declspec(dllexport)
i możesz pobrać informacje z pliku .map, jeśli włączysz tworzenie takich plików podczas kompilacji.Odbicie nie jest obsługiwane przez C ++ po wyjęciu z pudełka. Jest to smutne, ponieważ sprawia, że próby obronne są uciążliwe.
Istnieje kilka podejść do refleksji:
Pierwszy link wygląda najbardziej obiecująco (używa modów do clang), drugi omawia szereg technik, trzeci to inne podejście przy użyciu gcc:
http://www.donw.org/rfl/
https://bitbucket.org/dwilliamson/clreflect
https://root.cern.ch/how/how-use-reflex
Istnieje teraz grupa robocza ds. Refleksji nad C ++. Zobacz wiadomości dla C ++ 14 @ CERN:
Edytuj 13/08/17:
Od czasu oryginalnego postu nastąpiła pewna liczba potencjalnych postępów w tej refleksji. Poniżej podano więcej szczegółów i omówienie różnych technik i statusu:
Jednak nie wygląda obiecująco na znormalizowane podejście do refleksji w C ++ w najbliższej przyszłości, chyba że zainteresowanie społeczności wsparciem dla refleksji w C ++ będzie znacznie większe.
Poniżej przedstawiono szczegóły obecnego stanu na podstawie opinii z ostatniego spotkania standardów C ++:
Edytuj 13.12.2017
Wygląda na to, że refleksja zmierza w kierunku C ++ 20 lub więcej prawdopodobnie TSR. Ruch jest jednak powolny.
Edytuj 15/09/2018
Projekt TS został wysłany do organów krajowych w celu głosowania.
Tekst można znaleźć tutaj: https://github.com/cplusplus/reflection-ts
Edytuj 11/07/2019
Refleksja TS jest już ukończona i można ją komentować i głosować latem (2019).
Podejście programistyczne dla meta-szablonów należy zastąpić prostszym podejściem do kompilowania kodu czasu (nie odzwierciedlonym w TS).
Edytuj 10/02/2020
Tutaj jest prośba o wsparcie TS refleksji w Visual Studio:
Dyskusja na temat TS autor David Sankel:
http://cppnow.org/history/2019/talks/
https://www.youtube.com/watch?v=VMuML6vLSus&feature=youtu.be
Edytuj 17 marca 2020 r
Postępuje refleksja. Raport z „Raportu z podróży komitetu ISO C ++ w Pradze 2020-02” można znaleźć tutaj:
Szczegółowe informacje na temat tego, co jest rozważane w C ++ 23, można znaleźć tutaj (zawiera krótką sekcję Odbicie):
Edytuj 4 czerwca 2020 r
Jeff Preshing wydał nową platformę o nazwie „Plywood”, która zawiera mechanizm odzwierciedlania środowiska wykonawczego. Więcej informacji można znaleźć tutaj:
Narzędzia i podejście wydają się być jak dotąd najbardziej dopracowane i najłatwiejsze w użyciu.
źródło
Musisz spojrzeć na to, co próbujesz zrobić i czy RTTI spełni twoje wymagania. Zaimplementowałem własne pseudorefleksję do bardzo konkretnych celów. Na przykład kiedyś chciałem móc elastycznie konfigurować dane wyjściowe symulacji. Wymagało to dodania kodu typu „kocioł” do klas, które byłyby wyprowadzane:
Pierwsze wywołanie dodaje ten obiekt do systemu filtrującego, który wywołuje
BuildMap()
metodę, aby dowiedzieć się, jakie metody są dostępne.Następnie w pliku konfiguracyjnym możesz zrobić coś takiego:
Dzięki magii związanej z szablonami
boost
, jest to tłumaczone na serię wywołań metod w czasie wykonywania (gdy plik konfiguracyjny jest czytany), więc jest dość wydajne. Nie poleciłbym tego robić, chyba że naprawdę potrzebujesz, ale kiedy to zrobisz, możesz zrobić naprawdę fajne rzeczy.źródło
Poleciłbym używać Qt .
Istnieje licencja typu open source, a także licencja komercyjna.
źródło
Co próbujesz zrobić z refleksją?
Można użyć Boost cechy typu i typeof bibliotek jako ograniczonej formie refleksji kompilacji. Oznacza to, że możesz sprawdzać i modyfikować podstawowe właściwości typu przekazywanego do szablonu.
źródło
EDYCJA : CAMP nie jest już utrzymywany; dostępne są dwa widelce:
CAMP to licencjonowana biblioteka MIT (wcześniej LGPL), która dodaje refleksji do języka C ++. Nie wymaga określonego kroku wstępnego przetwarzania w kompilacji, ale powiązanie musi zostać wykonane ręcznie.
Obecna biblioteka Tegesoft korzysta ze Wzmocnienia, ale istnieje również rozwidlenie używające C ++ 11, które nie wymaga już Wzmocnienia .
źródło
Zrobiłem kiedyś coś, czego szukasz, i chociaż można uzyskać pewien poziom refleksji i dostęp do funkcji wyższego poziomu, ból głowy związany z konserwacją może nie być tego wart. Mój system został wykorzystany do całkowitego oddzielenia klas interfejsu użytkownika od logiki biznesowej poprzez delegację podobną do koncepcji Objective-C przekazywania i przekazywania wiadomości. Można to zrobić, tworząc klasę bazową, która jest zdolna do odwzorowywania symboli (użyłem puli ciągów, ale można to zrobić za pomocą wyliczeń, jeśli wolisz obsługę błędów błędów w czasie kompilacji nad całkowitą elastycznością) niż wskaźniki funkcji (w rzeczywistości nie wskaźniki funkcji czystych, ale coś podobnego do tego, co Boost ma z Boost.Funkcją - do której wtedy nie miałem dostępu). Możesz zrobić to samo dla zmiennych składowych, o ile masz jakąś wspólną klasę podstawową zdolną do reprezentowania dowolnej wartości. Cały system stanowił bezproblemowe wyłudzanie Kodowania i Delegowania Kluczowych Wartości z kilkoma efektami ubocznymi, które być może były warte tyle czasu, ile potrzeba, aby każda klasa, która używała systemu, dopasowała wszystkie swoje metody i członków do legalnych wezwań : 1) Każda klasa może wywoływać dowolną metodę z dowolnej innej klasy bez konieczności dołączania nagłówków lub pisania fałszywych klas podstawowych, aby interfejs mógł zostać wstępnie zdefiniowany dla kompilatora; oraz 2) Obiekty pobierające i ustawiające zmiennych składowych były łatwe do zapewnienia bezpieczeństwa wątków, ponieważ zmienianie lub uzyskiwanie dostępu do ich wartości odbywało się zawsze za pomocą 2 metod w klasie bazowej wszystkich obiektów. Cały system stanowił bezproblemowe wyłudzanie Kodowania i Delegowania Kluczowych Wartości z kilkoma efektami ubocznymi, które być może były warte tyle czasu, ile potrzeba, aby każda klasa, która używała systemu, dopasowała wszystkie swoje metody i członków do legalnych wezwań : 1) Każda klasa może wywoływać dowolną metodę z dowolnej innej klasy bez konieczności dołączania nagłówków lub pisania fałszywych klas podstawowych, aby interfejs mógł zostać wstępnie zdefiniowany dla kompilatora; oraz 2) Obiekty pobierające i ustawiające zmiennych składowych były łatwe do zapewnienia bezpieczeństwa wątków, ponieważ zmienianie lub uzyskiwanie dostępu do ich wartości odbywało się zawsze za pomocą 2 metod w klasie bazowej wszystkich obiektów. Cały system stanowił bezproblemowe wyłudzanie Kodowania i Delegowania Kluczowych Wartości z kilkoma efektami ubocznymi, które być może były warte tyle czasu, ile potrzeba, aby każda klasa, która używała systemu, dopasowała wszystkie swoje metody i członków do legalnych wezwań : 1) Każda klasa może wywoływać dowolną metodę z dowolnej innej klasy bez konieczności dołączania nagłówków lub pisania fałszywych klas podstawowych, aby interfejs mógł zostać wstępnie zdefiniowany dla kompilatora; oraz 2) Obiekty pobierające i ustawiające zmiennych składowych były łatwe do zapewnienia bezpieczeństwa wątków, ponieważ zmienianie lub uzyskiwanie dostępu do ich wartości odbywało się zawsze za pomocą 2 metod w klasie bazowej wszystkich obiektów. 1) Każda klasa może wywołać dowolną metodę z dowolnej innej klasy bez konieczności dołączania nagłówków lub pisania fałszywych klas podstawowych, aby interfejs mógł zostać wstępnie zdefiniowany dla kompilatora; oraz 2) Obiekty pobierające i ustawiające zmiennych składowych były łatwe do zapewnienia bezpieczeństwa wątków, ponieważ zmienianie lub uzyskiwanie dostępu do ich wartości odbywało się zawsze za pomocą 2 metod w klasie bazowej wszystkich obiektów. 1) Każda klasa może wywołać dowolną metodę z dowolnej innej klasy bez konieczności dołączania nagłówków lub pisania fałszywych klas podstawowych, aby interfejs mógł zostać wstępnie zdefiniowany dla kompilatora; oraz 2) Obiekty pobierające i ustawiające zmiennych składowych były łatwe do zapewnienia bezpieczeństwa wątków, ponieważ zmienianie lub uzyskiwanie dostępu do ich wartości odbywało się zawsze za pomocą 2 metod w klasie bazowej wszystkich obiektów.
Doprowadziło to również do możliwości robienia naprawdę dziwnych rzeczy, które w przeciwnym razie nie byłyby łatwe w C ++. Na przykład mogłem utworzyć obiekt Array, który zawierał dowolne elementy dowolnego typu, w tym siebie, i dynamicznie tworzyć nowe tablice, przekazując komunikat do wszystkich elementów tablicy i zbierając wartości zwracane (podobne do map w Lisp). Inną była implementacja obserwacji klucz-wartość, dzięki której mogłem skonfigurować interfejs użytkownika, aby natychmiast reagował na zmiany w elementach klas zaplecza zamiast ciągłego odpytywania danych lub niepotrzebnego przerysowywania wyświetlania.
Być może bardziej interesujący jest dla ciebie fakt, że możesz również zrzucić wszystkie metody i elementy zdefiniowane dla klasy, i nie mniej niż w formie łańcucha.
Wady systemu, które mogą zniechęcać do zawracania sobie głowy: dodawanie wszystkich wiadomości i kluczowych wartości jest niezwykle uciążliwe; jest wolniejszy niż bez odbicia; będzie wzrastać do nienawidzić widząc
boost::static_pointer_cast
iboost::dynamic_pointer_cast
całym swoim kodzie z gwałtownej namiętności; ograniczenia silnie typowanego systemu są nadal obecne, tak naprawdę po prostu je trochę ukrywasz, więc nie jest to takie oczywiste. Literówki w strunach również nie są zabawną ani łatwą do odkrycia niespodzianką.Co do tego, jak zaimplementować coś takiego: po prostu użyj wspólnych i słabych wskaźników do wspólnej bazy (moja była bardzo pomysłowo nazywana „Obiektem”) i uzyskaj wszystkie typy, których chcesz użyć. Poleciłbym zainstalować Boost.Function zamiast robić to tak, jak ja to zrobiłem, z jakimś niestandardowym badziewiem i mnóstwem brzydkich makr do zawijania wywołań wskaźnika funkcji. Ponieważ wszystko jest mapowane, sprawdzanie obiektów jest tylko kwestią iteracji przez wszystkie klucze. Ponieważ moje zajęcia były zasadniczo tak blisko bezpośredniego oderwania kakao, jak to możliwe przy użyciu tylko C ++, jeśli chcesz czegoś takiego, sugerowałbym użycie dokumentacji kakao jako planu.
źródło
Istnieje kolejna nowa biblioteka do refleksji w C ++, o nazwie RTTR (Refleksja czasu wykonania, patrz także github ).
Interfejs jest podobny do odbicie w C # i działa bez żadnych RTTI.
źródło
Dwa podobne do refleksji rozwiązania, które znam z moich dni w C ++:
1) Użyj RTTI, który zapewni Ci bootstrap, aby zbudować swoje zachowanie przypominające odbicie, jeśli jesteś w stanie uzyskać wszystkie swoje klasy, aby wywodziły się z klasy podstawowej „obiektowej”. Ta klasa mogłaby udostępnić niektóre metody, takie jak GetMethod, GetBaseClass itp. Jeśli chodzi o sposób działania tych metod, musisz ręcznie dodać niektóre makra, aby udekorować typy, które za kulisami tworzą metadane w typie, aby dostarczyć odpowiedzi na GetMethods itp.
2) Inną opcją, jeśli masz dostęp do obiektów kompilatora, jest użycie zestawu DIA SDK . Jeśli dobrze pamiętam, pozwala to na otwarcie pdbs, które powinno zawierać metadane dla twoich typów C ++. Może być wystarczające, aby zrobić to, czego potrzebujesz. Ta strona pokazuje, w jaki sposób można uzyskać na przykład wszystkie podstawowe typy klas.
Oba te rozwiązania są jednak trochę brzydkie! Nie ma nic takiego jak trochę C ++, abyś docenił luksus C #.
Powodzenia.
źródło
EDYCJA: Zaktualizowano niedziałający link 7 lutego 2017 r.
Myślę, że nikt o tym nie wspominał:
W CERN używają systemu pełnego odbicia dla C ++:
CERN Reflex . Wygląda na to, że działa bardzo dobrze.
źródło
To pytanie jest już trochę stare (nie wiem, dlaczego wciąż uderzam w stare pytania), ale myślałem o BOOST_FUSION_ADAPT_STRUCT, który wprowadza refleksję w czasie kompilacji.
Od Ciebie zależy mapowanie tego na odbicie w czasie rzeczywistym i nie będzie to zbyt łatwe, ale jest to możliwe w tym kierunku, podczas gdy nie byłoby odwrotnie :)
Naprawdę uważam, że makro do kapsułkowania tego
BOOST_FUSION_ADAPT_STRUCT
może wygenerować niezbędne metody, aby uzyskać zachowanie w czasie wykonywania.źródło
Myślę, że może zainteresować Cię artykuł „Korzystanie z szablonów do refleksji w C ++” autorstwa Dominica Filiona. Znajduje się w sekcji 1.4 Klejnotów do programowania gier 5 . Niestety nie mam przy sobie swojej kopii, ale poszukaj jej, ponieważ myślę, że wyjaśnia, o co prosisz.
źródło
Rozważać jest biblioteką refleksyjną C ++, w odpowiedzi na to pytanie. Rozważyłem opcje i zdecydowałem się stworzyć własną, ponieważ nie mogłem znaleźć takiej, która zaznaczyłaby wszystkie moje pola.
Chociaż są świetne odpowiedzi na to pytanie, nie chcę używać ton makr ani polegać na Boost. Boost to świetna biblioteka, ale istnieje wiele małych projektów C ++ 0x na zamówienie, które są prostsze i mają krótszy czas kompilacji. Są też zalety dekorowania klasy zewnętrznie, takie jak pakowanie biblioteki C ++, która (jeszcze?) Nie obsługuje C ++ 11. To rozwidlenie CAMP, używające C ++ 11, które nie wymaga już wzmocnienia .
źródło
Refleksja dotyczy zasadniczo tego, co kompilator postanowił pozostawić jako ślady w kodzie, który kod wykonawczy może zapytać. C ++ słynie z tego, że nie płaci za to, czego nie używasz; ponieważ większość ludzi nie używa / nie chce refleksji, kompilator C ++ unika kosztów, nie rejestrując niczego .
C ++ nie zapewnia refleksji i nie jest łatwo „zasymulować” go tak ogólnie, jak zauważyły to inne odpowiedzi.
W obszarze „inne techniki”, jeśli nie masz języka z refleksją, uzyskaj narzędzie, które może wyodrębnić potrzebne informacje w czasie kompilacji.
Nasz pakiet Deng Software Reengineering Toolkit to uogólniona technologia kompilatora sparametryzowana wyraźnymi definicjami języka. Ma definicje języka dla C, C ++, Java, COBOL, PHP, ...
W przypadku wersji C, C ++, Java i COBOL zapewnia pełny dostęp do drzew parsowanych i informacji o tablicy symboli. Ta informacja w tablicy symboli zawiera dane, których prawdopodobnie potrzebujesz od „refleksji”. Jeśli Twoim celem jest wyliczenie zestawu pól lub metod i zrobienie czegoś z nimi, DMS może zostać użyty do przekształcenia kodu zgodnie z tym, co znajdziesz w tabelach symboli w dowolny sposób.
źródło
Możesz znaleźć inną bibliotekę tutaj: http://www.garret.ru/cppreflection/docs/reflect.html Obsługuje 2 sposoby: uzyskanie informacji o typie z informacji debugowania i pozwolenie programiście na dostarczenie tych informacji.
Zainteresowałem się również refleksją nad moim projektem i znalazłem tę bibliotekę, jeszcze jej nie wypróbowałem, ale wypróbowałem inne narzędzia tego faceta i podoba mi się, jak działają :-)
źródło
Sprawdź Classdesc http://classdesc.sf.net . Zapewnia odbicie w postaci „deskryptorów” klasy, współpracuje z dowolnym standardowym kompilatorem C ++ (tak, wiadomo, że współpracuje z Visual Studio oraz GCC) i nie wymaga adnotacji kodu źródłowego (chociaż istnieją pewne pragmy do obsługi trudnych sytuacji ). Jest rozwijany od ponad dekady i wykorzystywany w wielu projektach na skalę przemysłową.
źródło
Kiedy chciałem się zastanowić w C ++, przeczytałem ten artykuł i poprawiłem to, co tam zobaczyłem. Niestety nie ma. Nie jestem właścicielem wyniku ... ale z pewnością możesz dostać to, co miałem i stamtąd.
Obecnie badam, kiedy mam na to ochotę, metody użycia inherit_linearly, aby znacznie ułatwić definiowanie typów odblaskowych. Zaszedłem dość daleko, ale wciąż mam wiele do zrobienia. Bardzo prawdopodobne jest, że zmiany w C ++ 0x będą bardzo pomocne w tym obszarze.
źródło
Wygląda na to, że C ++ nadal nie ma tej funkcji. I C ++ 11 również odroczył refleksję ((
Wyszukaj niektóre makra lub utwórz własne. Qt może również pomóc w odbiciu (jeśli można go użyć).
źródło
nawet jeśli odbicie nie jest obsługiwane w c ++, nie jest zbyt trudne do wdrożenia. Spotkałem ten świetny artykuł: http://replicaisland.blogspot.co.il/2010/11/building-reflective-object-system-in-c.html
artykuł szczegółowo wyjaśnia, w jaki sposób można wdrożyć dość prosty i podstawowy system refleksji. przyznał, że nie jest to najzdrowsze rozwiązanie, i zostały jeszcze szorstkie krawędzie do rozwiązania, ale na moje potrzeby było to wystarczające.
dolna linia - odbicie może się opłacić, jeśli wykonane poprawnie, i jest to całkowicie wykonalne w c ++.
źródło
Chciałbym reklamować istnienie automatycznego zestawu narzędzi introspekcji / refleksji „IDK”. Korzysta z meta-kompilatora takiego jak Qt i dodaje meta informacje bezpośrednio do plików obiektowych. Twierdzi się, że jest łatwy w użyciu. Brak zależności zewnętrznych. Pozwala nawet automatycznie odzwierciedlać std :: string, a następnie używać go w skryptach. Proszę spojrzeć na IDK
źródło
Jeśli szukasz względnie prostej refleksji w C ++ - zebrałem z różnych źródeł makro / definicje i skomentowałem ich działanie. Możesz pobrać pliki nagłówkowe stąd:
https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h
zestaw definicji, a na dodatek funkcjonalność:
https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h https://github.com/tapika/TestCppReflect/blob/master/CppReflect.cpp https://github.com/tapika/TestCppReflect/ blob / master / TypeTraits.h
Przykładowa aplikacja znajduje się również w repozytorium git, tutaj: https://github.com/tapika/TestCppReflect/
Częściowo skopiuję go tutaj z wyjaśnieniem:
REFLECTABLE
Zdefiniuj używa nazwy klasy + nazwy pola za pomocąoffsetof
- do określenia, w którym miejscu w pamięci znajduje się dane pole. Próbowałem podnieść NET terminologia tak daleko jak to możliwe, ale C ++ i C # są różne, więc nie jest to 1 do 1. Całe c ++ mieszka odbicie model inTypeInfo
iFieldInfo
klas.Użyłem parsera pugi xml, aby pobrać kod demo do xml i przywrócić go z xml.
Dane wyjściowe wygenerowane przez kod demonstracyjny wyglądają następująco:
Możliwe jest również włączenie dowolnej obsługi klasy / struktury innej firmy za pośrednictwem klasy TypeTraits i częściowej specyfikacji szablonu - w celu zdefiniowania własnej klasy TypeTraitsT, w podobny sposób jak CString lub int - patrz przykładowy kod w
https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195
To rozwiązanie dotyczy systemu Windows / Visual studio. Możliwe jest przeniesienie go do innych systemów operacyjnych / kompilatorów, ale jeszcze tego nie zrobił. (Zapytaj mnie, czy naprawdę podoba ci się rozwiązanie, może mogę ci pomóc)
To rozwiązanie ma zastosowanie do serializacji w jednym ujęciu jednej klasy z wieloma podklasami.
Jeśli jednak szukasz mechanizmu szeregowania części klasy lub nawet kontrolowania, jakie funkcje wywołują odbicia refleksyjne, możesz rzucić okiem na następujące rozwiązanie:
https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel
Bardziej szczegółowe informacje można znaleźć w filmie na youtube:
Odbicie typu środowiska wykonawczego C ++ https://youtu.be/TN8tJijkeFE
Próbuję wyjaśnić nieco głębiej, jak będzie działać odbicie c ++.
Przykładowy kod będzie wyglądał na przykład tak:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp
Ale każdy krok tutaj powoduje wywołanie funkcji Przy użyciu właściwości C ++ z
__declspec(property(get =, put ... )
.który otrzymuje pełne informacje o typach danych C ++, nazwach właściwości C ++ i wskaźnikach instancji klas, w formie ścieżki, i na podstawie tych informacji można wygenerować xml, json lub nawet serializować je przez Internet.
Przykłady takich wirtualnych funkcji zwrotnych można znaleźć tutaj:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp
Zobacz funkcje
ReflectCopy
i funkcję wirtualną::OnAfterSetProperty
.Ale ponieważ temat jest bardzo zaawansowany - polecam najpierw przejrzeć wideo.
Jeśli masz jakieś pomysły na ulepszenia, skontaktuj się ze mną.
źródło
Odbicie w C ++ jest bardzo przydatne, w przypadkach, w których musisz uruchomić jakąś metodę dla każdego członka (na przykład: serializacja, haszowanie, porównywanie). Przyszedłem z ogólnym rozwiązaniem o bardzo prostej składni:
Gdzie ENUMERATE_MEMBERS to makro, które zostanie opisane później (AKTUALIZACJA):
Załóżmy, że zdefiniowaliśmy funkcję serializacji dla int i std :: string w następujący sposób:
I mamy ogólną funkcję w pobliżu „tajnego makra”;)
Teraz możesz pisać
Zatem mając makro ENUMERATE_MEMBERS w definicji struktury, możesz tworzyć serializację, porównywać, mieszać i inne rzeczy bez dotykania oryginalnego typu, jedynym wymaganiem jest implementacja metody „EnumerateWith” dla każdego typu, który nie jest wyliczalny dla każdego modułu wyliczającego (jak BinaryWriter) . Zwykle będziesz musiał wdrożyć 10-20 „prostych” typów, aby obsłużyć dowolny typ w swoim projekcie.
To makro powinno mieć zerowy narzut w stosunku do tworzenia / niszczenia struktur w czasie wykonywania, a kod T.EnumerateWith () powinien być generowany na żądanie, co można osiągnąć przez utworzenie funkcji wstawiania szablonu, więc jedyny narzut w cała historia polega na dodaniu ENUMERATE_MEMBERS (m1, m2, m3 ...) do każdej struktury, podczas gdy implementacja określonej metody dla każdego typu elementu jest koniecznością w każdym rozwiązaniu, więc nie zakładam, że jest to narzut.
AKTUALIZACJA: Istnieje bardzo prosta implementacja makra ENUMERATE_MEMBERS (jednak można ją nieco rozszerzyć, aby obsługiwała dziedziczenie po strukturze wyliczalnej)
I nie potrzebujesz żadnej biblioteki innej firmy dla tych 15 linii kodu;)
źródło
Możesz uzyskać fajne funkcje odbicia statycznego dla struktur za pomocą BOOST_HANA_DEFINE_STRUCT z biblioteki Boost :: Hana.
Hana jest dość wszechstronna, nie tylko pod kątem zamierzonego zastosowania, ale także w przypadku wielu metaprogramowania szablonów.
źródło
Random Access Reflection zapewnia dość łatwą i intuicyjną refleksję - wszystkie informacje o polu / typie są zaprojektowane tak, aby były dostępne w tablicach lub czuły się jak dostęp do tablicy. Jest napisany dla C ++ 17 i współpracuje z Visual Studios, g ++ i Clang. Biblioteka ma tylko nagłówek, co oznacza, że potrzebujesz tylko skopiować plik „Reflect.h” do projektu, aby go użyć.
Odbite struktury lub klasy wymagają makra REFLECT, w którym podajesz nazwę klasy, którą odzwierciedlasz oraz nazwy pól.
To wszystko, nie potrzebujesz dodatkowego kodu, aby ustawić odbicie. Opcjonalnie możesz podać nadklasy (w nawiasach pierwszego argumentu) i adnotacje pól (w nawiasach poprzedzających pole, które chcesz opisać), aby móc przechodzić nadklasy lub dodawać dodatkowe informacje o czasie kompilacji do pola (takiego jak Json: :Ignorować).
Pętla przez pola może być tak prosta jak ...
Możesz przejść przez instancję obiektu, aby uzyskać dostęp do wartości pól (które możesz odczytać lub zmodyfikować) i informacji o typach pól ...
JSON biblioteka jest zbudowany na szczycie RandomAccessReflection które auto identyfikuje odpowiednie środki wyjściowe JSON do czytania lub pisania, a może rekurencyjnie przechodzić żadnych odbitych pól, a także tablice i kontenery STL.
Powyższe można uruchomić tak ...
Zobacz też...
źródło
Jeśli zadeklarujesz wskaźnik do funkcji takiej jak ta:
Możesz przypisać miejsce w pamięci do tej funkcji w ten sposób (wymaga
libdl
idlopen
)Aby załadować symbol lokalny za pomocą pośrednictwa, możesz użyć
dlopen
na wywołanie binarne (argv[0]
).Jedynym wymaganiem (innym niż
dlopen()
,libdl
idlfcn.h
) jest znajomość argumentów i rodzaju funkcji.źródło