Saya ingin dapat mengintrospeksi kelas C ++ untuk nama, isinya (yaitu anggota dan tipenya) dll. Saya berbicara asli C ++ di sini, tidak dikelola C ++, yang memiliki refleksi. Saya menyadari C ++ menyediakan beberapa informasi terbatas menggunakan RTTI. Perpustakaan tambahan apa (atau teknik lain) yang bisa memberikan informasi ini?
c++
reflection
templates
sfinae
Nick
sumber
sumber
Jawaban:
Yang perlu Anda lakukan adalah memiliki preprocessor menghasilkan data refleksi tentang bidang. Data ini dapat disimpan sebagai kelas bersarang.
Pertama, untuk membuatnya lebih mudah dan lebih bersih untuk menulisnya di preprocessor kita akan menggunakan ekspresi yang diketik. Ekspresi yang diketik hanyalah ekspresi yang menempatkan jenis dalam tanda kurung. Jadi, alih-alih menulis,
int x
Anda akan menulis(int) x
. Berikut adalah beberapa makro berguna untuk membantu dengan ekspresi yang diketik:Selanjutnya, kami mendefinisikan
REFLECTABLE
makro untuk menghasilkan data tentang setiap bidang (ditambah bidang itu sendiri). Makro ini akan disebut seperti ini:Jadi menggunakan Boost.PP kita beralih pada setiap argumen dan menghasilkan data seperti ini:
Apa yang dilakukan adalah menghasilkan konstanta
fields_n
yang merupakan jumlah bidang yang dapat dipantulkan di kelas. Maka itu spesialisasifield_data
untuk setiap bidang. Ini juga temanreflector
kelas, ini sehingga dapat mengakses bidang bahkan ketika mereka pribadi:Sekarang untuk beralih ke bidang yang kita gunakan pola pengunjung. Kami membuat rentang MPL dari 0 hingga jumlah bidang, dan mengakses data bidang pada indeks itu. Kemudian data lapangan diteruskan ke pengunjung yang disediakan pengguna:
Sekarang untuk momen kebenaran, kami menggabungkan semuanya. Inilah cara kita mendefinisikan
Person
kelas yang dapat dipantulkan:Berikut adalah
print_fields
fungsi umum yang menggunakan data refleksi untuk beralih di bidang:Contoh menggunakan
print_fields
denganPerson
kelas yang dapat dipantulkan :Output yang mana:
Dan voila, kami baru saja mengimplementasikan refleksi dalam C ++, di bawah 100 baris kode.
sumber
#define DETAIL_TYPEOF_INT2(tuple) DETAIL_TYPEOF_HEAD tuple
dan#define DETAIL_TYPEOF_INT(...) DETAIL_TYPEOF_INT2((__VA_ARGS__))
dan ubah definisi TYPEOF (x) ke:#define TYPEOF(x) DETAIL_TYPEOF_INT(DETAIL_TYPEOF_PROBE x,)
Ada dua macam
reflection
berenang di sekitar.Ini tidak mungkin dengan C ++.
Hal semacam ini dimungkinkan dengan menggunakan C ++
template-tricks
. Menggunakanboost::type_traits
untuk banyak hal (seperti memeriksa apakah suatu tipe integral). Untuk memeriksa keberadaan fungsi anggota, gunakan Apakah mungkin untuk menulis templat untuk memeriksa keberadaan fungsi? . Untuk memeriksa apakah ada tipe bersarang tertentu, gunakan SFINAE biasa .Jika Anda mencari cara untuk mencapai 1), seperti melihat berapa banyak metode yang dimiliki kelas, atau seperti mendapatkan representasi string dari id kelas, maka saya khawatir tidak ada cara Standar C ++ untuk melakukan ini. Anda harus menggunakan keduanya
C ++ dibuat dengan kecepatan dalam pikiran. Jika Anda ingin inspeksi tingkat tinggi, seperti C # atau Java, maka saya khawatir saya harus memberi tahu Anda tidak ada cara tanpa usaha.
sumber
members<T>
yang mengembalikan daftar semua anggota T. Jika kita ingin memiliki refleksi runtime (yaitu RTTI dicampur dengan refleksi), kompiler masih akan tahu semua tipe dasar yang dipantulkan. Kemungkinan besarmembers<T>(T&)
tidak akan pernah dipakai untuk T = std :: string, jadi RTTI untuk std :: string atau kelas turunannya tidak perlu dimasukkan.Dan saya akan suka kuda poni, tetapi kuda poni tidak gratis. :-p
http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI adalah apa yang akan Anda dapatkan. Refleksi seperti yang Anda pikirkan - metadata deskriptif penuh tersedia saat runtime - tidak ada untuk C ++ secara default.
sumber
Informasi itu ada - tetapi tidak dalam format yang Anda butuhkan, dan hanya jika Anda mengekspor kelas Anda. Ini berfungsi di Windows, saya tidak tahu tentang platform lain. Menggunakan specifier kelas penyimpanan seperti pada, misalnya:
Ini membuat kompiler membuat data definisi kelas ke dalam DLL / Exe. Tapi itu tidak dalam format yang dapat Anda gunakan untuk refleksi.
Di perusahaan saya, kami membangun perpustakaan yang menginterpretasikan metadata ini, dan memungkinkan Anda untuk merefleksikan kelas tanpa memasukkan makro dll, ke dalam kelas itu sendiri. Ini memungkinkan fungsi dipanggil sebagai berikut:
Ini secara efektif tidak:
Fungsi Invoke (this_pointer, ...) memiliki argumen variabel. Tentunya dengan memanggil fungsi dengan cara ini Anda menghindari hal-hal seperti const-safety dan sebagainya, sehingga aspek-aspek ini diimplementasikan sebagai pemeriksaan runtime.
Saya yakin sintaksnya dapat ditingkatkan, dan ini hanya berfungsi pada Win32 dan Win64 sejauh ini. Kami merasa sangat berguna untuk memiliki antarmuka GUI otomatis ke kelas, membuat properti di C ++, streaming ke dan dari XML dan sebagainya, dan tidak perlu diturunkan dari kelas dasar tertentu. Jika ada permintaan yang cukup mungkin kita bisa mengetuknya agar rilis.
sumber
__declspec(dllexport)
dan Anda dapat mengambil informasi dari file .map jika Anda mengaktifkan pembuatannya selama membangun.Refleksi tidak didukung oleh C ++ di luar kotak. Ini menyedihkan karena membuat tes pertahanan menjadi sakit.
Ada beberapa pendekatan untuk melakukan refleksi:
Tautan pertama terlihat paling menjanjikan (menggunakan mod untuk berdering), yang kedua membahas sejumlah teknik, yang ketiga adalah pendekatan yang berbeda menggunakan gcc:
http://www.donw.org/rfl/
https://bitbucket.org/dwilliamson/clreflect
https://root.cern.ch/how/how-use-reflex
Sekarang ada kelompok kerja untuk refleksi C ++. Lihat berita untuk C ++ 14 @ CERN:
Edit 13/08/17:
Sejak posting asli telah ada sejumlah kemajuan potensial pada refleksi. Berikut ini memberikan lebih banyak detail dan diskusi tentang berbagai teknik dan status:
Namun itu tidak terlihat menjanjikan pada pendekatan refleksi standar dalam C ++ dalam waktu dekat kecuali ada banyak minat dari masyarakat dalam mendukung refleksi dalam C ++.
Berikut ini rincian status saat ini berdasarkan umpan balik dari pertemuan standar C ++ terakhir:
Edit 13/12/2017
Refleksi terlihat bergerak menuju C ++ 20 atau lebih mungkin TSR. Namun gerakannya lambat.
Edit 15/09/2018
Draf TS telah dikirim ke badan nasional untuk pemungutan suara.
Teks dapat ditemukan di sini: https://github.com/cplusplus/reflection-ts
Edit 11/07/2019
TS refleksi adalah fitur lengkap dan keluar untuk komentar dan memilih selama musim panas (2019).
Pendekatan pemrograman meta-template harus diganti dengan pendekatan kode waktu kompilasi yang lebih sederhana (tidak tercermin dalam TS).
Edit 10/02/2020
Ada permintaan untuk mendukung TS refleksi di Visual Studio di sini:
Bicara di TS oleh penulis David Sankel:
http://cppnow.org/history/2019/talks/
https://www.youtube.com/watch?v=VMuML6vLSus&feature=youtu.be
Sunting 17 Maret 2020
Kemajuan refleksi sedang dibuat. Laporan dari '2020-02 Praha ISO C ++ Laporan Perjalanan Komite' dapat ditemukan di sini:
Detail tentang apa yang sedang dipertimbangkan untuk C ++ 23 dapat ditemukan di sini (termasuk bagian pendek tentang Refleksi):
Sunting 4 Juni 2020
Kerangka kerja baru telah dirilis oleh Jeff Preshing yang disebut 'Plywood' yang berisi mekanisme untuk refleksi runtime. Lebih detail dapat ditemukan di sini:
Alat dan pendekatannya terlihat paling halus dan paling mudah digunakan sejauh ini.
sumber
Anda perlu melihat apa yang Anda coba lakukan, dan apakah RTTI akan memenuhi kebutuhan Anda. Saya telah menerapkan pseudo-refleksi saya sendiri untuk beberapa tujuan yang sangat spesifik. Sebagai contoh, saya pernah ingin dapat secara fleksibel mengkonfigurasi apa yang akan dihasilkan oleh simulasi. Diperlukan menambahkan beberapa kode boilerplate ke kelas yang akan di-output:
Panggilan pertama menambahkan objek ini ke sistem penyaringan, yang memanggil
BuildMap()
metode untuk mencari tahu metode apa yang tersedia.Kemudian, dalam file konfigurasi, Anda dapat melakukan sesuatu seperti ini:
Melalui beberapa templat sulap yang melibatkan
boost
, ini akan diterjemahkan ke dalam serangkaian panggilan metode pada saat run-time (ketika file konfigurasi dibaca), sehingga cukup efisien. Saya tidak akan merekomendasikan melakukan ini kecuali Anda benar-benar perlu, tetapi, ketika Anda melakukannya, Anda dapat melakukan beberapa hal yang sangat keren.sumber
Saya akan merekomendasikan menggunakan Qt .
Ada lisensi sumber terbuka serta lisensi komersial.
sumber
Apa yang Anda coba lakukan dengan refleksi?
Anda dapat menggunakan sifat tipe Boost dan tipe perpustakaan sebagai bentuk refleksi kompilasi waktu terbatas. Artinya, Anda dapat memeriksa dan memodifikasi properti dasar dari jenis yang diteruskan ke templat.
sumber
EDIT : CAMP tidak lagi dipertahankan; dua garpu tersedia:
CAMP adalah perpustakaan berlisensi MIT (sebelumnya LGPL) yang menambahkan refleksi ke bahasa C ++. Itu tidak memerlukan langkah preprocessing spesifik dalam kompilasi, tetapi mengikat harus dilakukan secara manual.
Pustaka Tegesoft saat ini menggunakan Boost, tetapi ada juga garpu menggunakan C ++ 11 yang tidak lagi membutuhkan Boost .
sumber
Saya melakukan sesuatu seperti apa yang Anda cari sekali, dan sementara itu mungkin untuk mendapatkan beberapa tingkat refleksi dan akses ke fitur tingkat yang lebih tinggi, sakit kepala pemeliharaan mungkin tidak sepadan. Sistem saya digunakan untuk menjaga kelas UI sepenuhnya terpisah dari logika bisnis melalui pendelegasian yang mirip dengan konsep Objective-C tentang penerusan dan penerusan pesan. Cara untuk melakukannya adalah dengan membuat beberapa kelas dasar yang mampu memetakan simbol (saya menggunakan string pool tetapi Anda bisa melakukannya dengan enum jika Anda lebih suka penanganan kesalahan waktu dan kompilasi-waktu atas fleksibilitas total) ke pointer fungsi (sebenarnya tidak pointer fungsi murni, tetapi sesuatu yang mirip dengan apa yang Boost miliki dengan Boost.Fungsi - yang saya tidak punya akses pada saat itu). Anda dapat melakukan hal yang sama untuk variabel anggota Anda selama Anda memiliki beberapa kelas dasar umum yang mampu mewakili nilai apa pun. Seluruh sistem adalah ripoff Key-Value Coding dan Delegation yang tidak malu-malu, dengan beberapa efek samping yang mungkin sepadan dengan jumlah waktu yang diperlukan untuk membuat setiap kelas yang menggunakan sistem untuk mencocokkan semua metode dan anggota dengan panggilan hukum : 1) Setiap kelas dapat memanggil metode apa pun pada kelas lain tanpa harus menyertakan header atau menulis kelas dasar palsu sehingga antarmuka dapat ditentukan sebelumnya untuk kompiler; dan 2) Getter dan setter dari variabel anggota mudah untuk membuat thread-safe karena mengubah atau mengakses nilai-nilai mereka selalu dilakukan melalui 2 metode di kelas dasar semua objek. Seluruh sistem adalah ripoff Key-Value Coding dan Delegation yang tidak malu-malu, dengan beberapa efek samping yang mungkin sepadan dengan jumlah waktu yang diperlukan untuk membuat setiap kelas yang menggunakan sistem untuk mencocokkan semua metode dan anggota dengan panggilan hukum : 1) Setiap kelas dapat memanggil metode apa pun pada kelas lain tanpa harus menyertakan header atau menulis kelas dasar palsu sehingga antarmuka dapat ditentukan sebelumnya untuk kompiler; dan 2) Getter dan setter dari variabel anggota mudah untuk membuat thread-safe karena mengubah atau mengakses nilai-nilai mereka selalu dilakukan melalui 2 metode di kelas dasar semua objek. Seluruh sistem adalah ripoff Key-Value Coding dan Delegation yang tidak malu-malu, dengan beberapa efek samping yang mungkin sepadan dengan jumlah waktu yang diperlukan untuk membuat setiap kelas yang menggunakan sistem untuk mencocokkan semua metode dan anggota dengan panggilan hukum : 1) Setiap kelas dapat memanggil metode apa pun pada kelas lain tanpa harus menyertakan header atau menulis kelas dasar palsu sehingga antarmuka dapat ditentukan sebelumnya untuk kompiler; dan 2) Getter dan setter dari variabel anggota mudah untuk membuat thread-safe karena mengubah atau mengakses nilai-nilai mereka selalu dilakukan melalui 2 metode di kelas dasar semua objek. 1) Setiap kelas dapat memanggil metode apa pun pada kelas lain tanpa harus menyertakan header atau menulis kelas dasar palsu sehingga antarmuka dapat ditentukan sebelumnya untuk kompiler; dan 2) Getter dan setter dari variabel anggota mudah untuk membuat thread-safe karena mengubah atau mengakses nilai-nilai mereka selalu dilakukan melalui 2 metode di kelas dasar semua objek. 1) Setiap kelas dapat memanggil metode apa pun pada kelas lain tanpa harus menyertakan header atau menulis kelas dasar palsu sehingga antarmuka dapat ditentukan sebelumnya untuk kompiler; dan 2) Getter dan setter dari variabel anggota mudah untuk membuat thread-safe karena mengubah atau mengakses nilai-nilai mereka selalu dilakukan melalui 2 metode di kelas dasar semua objek.
Ini juga mengarah pada kemungkinan melakukan beberapa hal yang sangat aneh yang sebaliknya tidak mudah di C ++. Misalnya saya bisa membuat objek Array yang berisi item sembarang jenis apa pun, termasuk dirinya sendiri, dan membuat array baru secara dinamis dengan mengirimkan pesan ke semua item array dan mengumpulkan nilai kembali (mirip dengan peta di Lisp). Yang lain adalah implementasi mengamati nilai-kunci, di mana saya bisa mengatur UI untuk segera menanggapi perubahan dalam anggota kelas backend bukannya terus-menerus mengumpulkan data atau menggambar ulang tampilan yang tidak perlu.
Mungkin yang lebih menarik bagi Anda adalah kenyataan bahwa Anda juga dapat membuang semua metode dan anggota yang ditentukan untuk kelas, dan dalam bentuk string tidak kurang.
Kerugian pada sistem yang mungkin membuat Anda tidak ingin repot: menambahkan semua pesan dan nilai kunci sangat membosankan; lebih lambat daripada tanpa refleksi; Anda akan tumbuh membenci melihat
boost::static_pointer_cast
danboost::dynamic_pointer_cast
seluruh basis kode Anda dengan hasrat keras; keterbatasan sistem yang sangat diketik masih ada, Anda benar-benar hanya menyembunyikannya sedikit sehingga tidak sejelas itu. Kesalahan ketik dalam string Anda juga bukan kejutan yang menyenangkan atau mudah ditemukan.Mengenai cara mengimplementasikan sesuatu seperti ini: cukup gunakan pointer yang dibagi dan lemah ke beberapa basis umum (milik saya sangat imajinatif disebut "Objek") dan turunkan untuk semua jenis yang ingin Anda gunakan. Saya akan merekomendasikan menginstal Boost.Fungsi daripada melakukannya dengan cara yang saya lakukan, yang dengan beberapa omong kosong kustom dan satu ton makro jelek untuk membungkus panggilan fungsi pointer. Karena semuanya dipetakan, menginspeksi objek hanyalah masalah iterasi melalui semua kunci. Karena kelas saya pada dasarnya sedekat dengan ripoff langsung Cocoa mungkin hanya menggunakan C ++, jika Anda menginginkan sesuatu seperti itu maka saya sarankan menggunakan dokumentasi Cocoa sebagai cetak biru.
sumber
Ada perpustakaan baru untuk refleksi di C ++, yang disebut RTTR (Run Time Type Reflection, lihat juga github ).
Antarmuka mirip dengan refleksi dalam C # dan berfungsi tanpa RTTI.
sumber
Dua solusi seperti refleksi yang saya ketahui dari hari C ++ saya adalah:
1) Gunakan RTTI, yang akan menyediakan bootstrap bagi Anda untuk membangun perilaku seperti refleksi Anda, jika Anda bisa membuat semua kelas Anda berasal dari kelas dasar 'objek'. Kelas itu dapat memberikan beberapa metode seperti GetMethod, GetBaseClass dll. Adapun cara kerja metode-metode tersebut Anda perlu menambahkan beberapa makro secara manual untuk menghias tipe Anda, yang di belakang layar membuat metadata dalam tipe tersebut untuk memberikan jawaban kepada GetMethods dll.
2) Pilihan lain, jika Anda memiliki akses ke objek kompiler adalah menggunakan DIA SDK . Jika saya ingat dengan benar, ini memungkinkan Anda membuka pdb, yang seharusnya berisi metadata untuk tipe C ++ Anda. Mungkin cukup untuk melakukan apa yang Anda butuhkan. Halaman ini menunjukkan bagaimana Anda bisa mendapatkan semua tipe dasar kelas misalnya.
Kedua solusi ini agak jelek! Tidak ada yang seperti sedikit C ++ untuk membuat Anda menghargai kemewahan C #.
Semoga berhasil.
sumber
EDIT: Tautan rusak yang diperbarui pada tanggal 7 Februari 2017.
Saya pikir tidak ada yang menyebutkan ini:
Di CERN mereka menggunakan sistem refleksi penuh untuk C ++:
Refleks CERN . Tampaknya bekerja dengan sangat baik.
sumber
Pertanyaan ini agak lama sekarang (tidak tahu mengapa saya terus memukul pertanyaan lama hari ini) tetapi saya sedang memikirkan BOOST_FUSION_ADAPT_STRUCT yang memperkenalkan refleksi waktu kompilasi.
Terserah kepada Anda untuk memetakan ini ke run-time reflection tentu saja, dan itu tidak akan terlalu mudah, tetapi mungkin dalam arah ini, sementara itu tidak akan terbalik :)
Saya benar-benar berpikir makro untuk merangkum yang
BOOST_FUSION_ADAPT_STRUCT
bisa menghasilkan metode yang diperlukan untuk mendapatkan perilaku runtime.sumber
Saya pikir Anda mungkin menemukan artikel yang menarik "Menggunakan Template untuk Refleksi dalam C ++" oleh Dominic Filion. Itu ada di bagian 1.4 dari Pemrograman Game Permata 5 . Sayangnya saya tidak membawa salinan saya, tetapi mencarinya karena saya pikir itu menjelaskan apa yang Anda minta.
sumber
Merenungkan adalah perpustakaan refleksi C ++, dalam menjawab pertanyaan ini. Saya mempertimbangkan opsi dan memutuskan untuk membuat pilihan saya sendiri karena saya tidak dapat menemukan yang mencentang semua kotak saya.
Meskipun ada jawaban bagus untuk pertanyaan ini, saya tidak ingin menggunakan banyak makro, atau mengandalkan Boost. Boost adalah pustaka yang hebat, tetapi ada banyak proyek kecil C ++ 0 dipesan lebih dahulu yang lebih sederhana dan memiliki waktu kompilasi yang lebih cepat. Ada juga keuntungan untuk dapat mendekorasi kelas secara eksternal, seperti membungkus pustaka C ++ yang tidak (belum?) Mendukung C ++ 11. Ini adalah fork dari CAMP, menggunakan C ++ 11, yang tidak lagi membutuhkan Boost .
sumber
Refleksi pada dasarnya adalah tentang apa yang diputuskan oleh kompiler untuk meninggalkan jejak kaki dalam kode yang dapat ditanyakan oleh kode runtime. C ++ terkenal karena tidak membayar untuk apa yang tidak Anda gunakan; karena kebanyakan orang tidak menggunakan / menginginkan refleksi, kompiler C ++ menghindari biaya dengan tidak merekam apa pun .
Jadi, C ++ tidak memberikan refleksi, dan tidak mudah untuk "mensimulasikan" sendiri sebagai aturan umum seperti yang dicatat oleh jawaban lain.
Di bawah "teknik lain", jika Anda tidak memiliki bahasa dengan refleksi, dapatkan alat yang dapat mengekstrak informasi yang Anda inginkan pada waktu kompilasi.
Perangkat Rekayasa Ulang Perangkat Lunak DMS Kami adalah teknologi kompiler umum yang diparameterisasi dengan definisi langauge eksplisit. Ini memiliki definisi langauge untuk C, C ++, Java, COBOL, PHP, ...
Untuk versi C, C ++, Java dan COBOL, ia menyediakan akses lengkap ke pohon parse, dan informasi tabel simbol. Informasi tabel simbol itu termasuk jenis data yang mungkin Anda inginkan dari "refleksi". Jika tujuan Anda adalah untuk menghitung beberapa set bidang atau metode dan melakukan sesuatu dengannya, DMS dapat digunakan untuk mengubah kode sesuai dengan apa yang Anda temukan di tabel simbol dengan cara sewenang-wenang.
sumber
Anda dapat menemukan perpustakaan lain di sini: http://www.garret.ru/cppreflection/docs/reflect.html Mendukung 2 cara: mendapatkan informasi jenis dari informasi debug dan membiarkan programmer untuk memberikan informasi ini.
Saya juga tertarik pada refleksi untuk proyek saya dan menemukan perpustakaan ini, saya belum mencobanya, tetapi mencoba alat-alat lain dari orang ini dan saya suka cara kerjanya :-)
sumber
Lihat Classdesc http://classdesc.sf.net . Ini memberikan refleksi dalam bentuk "deskriptor" kelas, bekerja dengan kompiler C ++ standar apa pun (ya diketahui bekerja dengan Visual Studio dan juga GCC), dan tidak memerlukan anotasi kode sumber (meskipun beberapa pragma ada untuk menangani situasi sulit ). Ini telah dikembangkan selama lebih dari satu dekade, dan digunakan dalam sejumlah proyek skala industri.
sumber
Ketika saya ingin refleksi dalam C ++ saya membaca artikel ini dan meningkatkan apa yang saya lihat di sana. Maaf, tidak bisa. Saya tidak memiliki hasilnya ... tetapi Anda pasti bisa mendapatkan apa yang saya miliki dan pergi dari sana.
Saat ini saya sedang meneliti, ketika saya merasa seperti itu, metode untuk menggunakan inherit_linearly untuk membuat definisi tipe yang mudah dipantulkan jauh lebih mudah. Sebenarnya saya sudah cukup jauh di dalamnya tetapi saya masih memiliki cara untuk pergi. Perubahan dalam C ++ 0x sangat mungkin banyak membantu di bidang ini.
sumber
Sepertinya C ++ masih tidak memiliki fitur ini. Dan C ++ 11 refleksi tertunda juga ((
Cari beberapa makro atau buat sendiri. Qt juga dapat membantu refleksi (jika dapat digunakan).
sumber
meskipun refleksi tidak didukung di luar kotak di c ++, itu tidak terlalu sulit untuk diterapkan. Saya telah menemukan artikel yang bagus ini: http://replicaisland.blogspot.co.il/2010/11/building-reflective-object-system-in-c.html
artikel ini menjelaskan dengan sangat rinci bagaimana Anda dapat menerapkan sistem refleksi yang sangat sederhana dan belum sempurna. diberikan itu bukan solusi yang paling sehat, dan ada tepi kasar yang tersisa untuk diselesaikan tetapi untuk kebutuhan saya itu sudah cukup.
intinya - refleksi dapat membayar jika dilakukan dengan benar, dan itu sepenuhnya layak di c ++.
sumber
Saya ingin mengiklankan keberadaan perangkat introspeksi / refleksi otomatis "IDK". Ia menggunakan meta-compiler seperti Qt's dan menambahkan informasi meta langsung ke file objek. Itu diklaim mudah digunakan. Tidak ada ketergantungan eksternal. Bahkan memungkinkan Anda untuk secara otomatis mencerminkan std :: string dan kemudian menggunakannya dalam skrip. Silakan lihat IDK
sumber
Jika Anda mencari refleksi C ++ yang relatif sederhana - Saya telah mengumpulkan dari berbagai sumber makro / mendefinisikan, dan berkomentar bagaimana cara kerjanya. Anda dapat mengunduh file tajuk dari sini:
https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h
set definisi, ditambah fungsionalitas di atasnya:
https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h https://github.com/tapika/TestCppReflect/blob/master/CppReflect.cpp https://github.com/tapika/TestCppefef/ gumpalan / master / TypeTraits.h
Contoh aplikasi juga berada di repositori git, di sini: https://github.com/tapika/TestCppReflect/
Saya akan menyalinnya di sini dengan penjelasan:
REFLECTABLE
define menggunakan nama kelas + nama bidang denganoffsetof
- untuk mengidentifikasi di mana tempat dalam memori bidang tertentu berada. Saya telah mencoba untuk mengambil .NET terminologi sejauh mungkin, tetapi C ++ dan C # berbeda, jadi bukan 1 banding 1. Seluruh model refleksi C ++ berada di dalamTypeInfo
danFieldInfo
kelas.Saya telah menggunakan pugi xml parser untuk mengambil kode demo ke xml dan mengembalikannya dari xml.
Jadi output yang dihasilkan oleh kode demo terlihat seperti ini:
Dimungkinkan juga untuk mengaktifkan dukungan kelas / struktur pihak ke-3 apa pun melalui kelas TypeTraits, dan spesifikasi templat parsial - untuk menentukan kelas TypeTraitsT Anda sendiri, dengan cara yang mirip dengan CString atau int - lihat contoh kode di
https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195
Solusi ini berlaku untuk Windows / Visual studio. Dimungkinkan untuk porting ke OS / kompiler lain, tetapi belum melakukannya. (Tanyakan kepada saya jika Anda benar-benar menyukai solusi, saya mungkin dapat membantu Anda)
Solusi ini berlaku untuk serialisasi satu shot dari satu kelas dengan beberapa subclass.
Namun, jika Anda mencari mekanisme untuk membuat serial bagian-bagian kelas atau bahkan untuk mengontrol apa yang dihasilkan oleh fungsi refleksi, Anda dapat melihat solusi berikut:
https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel
Informasi lebih rinci dapat ditemukan dari video youtube:
C ++ Refleksi Jenis Runtime https://youtu.be/TN8tJijkeFE
Saya mencoba menjelaskan sedikit lebih dalam tentang bagaimana c ++ refleksi akan bekerja.
Contoh kode akan terlihat seperti contoh ini:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp
Tetapi setiap langkah di sini sebenarnya menghasilkan panggilan fungsi Menggunakan properti C ++ dengan
__declspec(property(get =, put ... )
.yang menerima informasi lengkap tentang Tipe Data C ++, nama properti C ++ dan pointer instance kelas, dalam bentuk path, dan berdasarkan informasi itu Anda dapat menghasilkan xml, json, atau bahkan membuat serialisasi yang satu melalui internet.
Contoh fungsi panggilan balik virtual tersebut dapat ditemukan di sini:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp
Lihat fungsi
ReflectCopy
, dan fungsi virtual::OnAfterSetProperty
.Tapi karena topiknya benar-benar canggih - saya sarankan untuk memeriksa melalui video terlebih dahulu.
Jika Anda memiliki beberapa ide perbaikan, jangan ragu untuk menghubungi saya.
sumber
The Random Access Refleksi perpustakaan membuat cukup mudah dan refleksi intuitif - semua informasi bidang / jenis ini dirancang untuk baik tersedia di array atau merasa seperti akses array. Ini ditulis untuk C ++ 17 dan bekerja dengan Visual Studios, g ++, dan Dentang. Pustaka adalah hanya tajuk, artinya Anda hanya perlu menyalin "Reflect.h" ke proyek Anda untuk menggunakannya.
Struct atau kelas yang direfleksikan membutuhkan makro REFLECT, di mana Anda memberikan nama kelas yang Anda refleksi dan nama-nama bidang.
Itu semua ada, tidak ada kode tambahan yang diperlukan untuk mengatur refleksi. Secara opsional Anda dapat menyediakan kacamata super (dalam tanda kurung argumen pertama) dan anotasi bidang (dalam tanda kurung yang mendahului bidang yang ingin Anda beri catatan) untuk dapat melintasi kacamata super atau menambahkan informasi waktu kompilasi tambahan ke bidang (seperti Json: :Mengabaikan).
Perulangan melalui bidang bisa sesederhana ...
Anda dapat mengulang melalui instance objek untuk mengakses nilai bidang (yang dapat Anda baca atau modifikasi) dan informasi jenis bidang ...
Sebuah JSON Perpustakaan dibangun di atas RandomAccessReflection yang otomatis mengidentifikasi representasi keluaran JSON tepat untuk membaca atau menulis, dan secara rekursif dapat melintasi setiap bidang tercermin, serta array dan kontainer STL.
Di atas bisa dijalankan seperti ...
Lihat juga...
sumber
Refleksi dalam C ++ sangat berguna, dalam kasus di sana Anda perlu menjalankan beberapa metode untuk setiap anggota (Misalnya: serialisasi, hashing, bandingkan). Saya datang dengan solusi umum, dengan sintaks yang sangat sederhana:
Di mana ENUMERATE_MEMBERS adalah makro, yang dijelaskan nanti (PEMBARUAN):
Asumsikan kita telah mendefinisikan fungsi serialisasi untuk int dan std :: string seperti ini:
Dan kami memiliki fungsi generik di dekat "makro rahasia";)
Sekarang kamu bisa menulis
Jadi dengan memiliki ENUMERATE_MEMBERS makro dalam definisi struct, Anda dapat membangun serialisasi, membandingkan, hashing, dan hal-hal lain tanpa menyentuh tipe asli, satu-satunya persyaratan adalah menerapkan metode "EnumerateWith" untuk setiap jenis, yang tidak dapat dihitung, per enumerator (seperti BinaryWriter) . Biasanya Anda harus menerapkan 10-20 jenis "sederhana" untuk mendukung jenis apa pun dalam proyek Anda.
Makro ini harus memiliki nol-overhead untuk pembuatan / penghancuran struct dalam run-time, dan kode T.EnumerateWith () harus dihasilkan sesuai permintaan, yang dapat dicapai dengan membuatnya fungsi templat-inline, jadi satu-satunya overhead di semua ceritanya adalah untuk menambahkan ENUMERATE_MEMBERS (m1, m2, m3 ...) ke setiap struct, sementara menerapkan metode spesifik per jenis anggota adalah suatu keharusan dalam solusi apa pun, jadi saya tidak menganggapnya sebagai overhead.
UPDATE: Ada implementasi makro ENUMERATE_MEMBERS yang sangat sederhana (namun bisa sedikit diperluas untuk mendukung warisan dari enumerable struct)
Dan Anda tidak perlu perpustakaan pihak ke-3 untuk 15 baris kode ini;)
sumber
Anda dapat mencapai fitur refleksi statis yang keren untuk struct dengan BOOST_HANA_DEFINE_STRUCT dari Boost :: Hana library.
Hana cukup fleksibel, tidak hanya untuk penggunaan yang Anda pikirkan tetapi untuk banyak pemrograman metaplat.
sumber
Jika Anda mendeklarasikan pointer ke fungsi seperti ini:
Anda dapat menetapkan tempat di memori untuk fungsi seperti ini (membutuhkan
libdl
dandlopen
)Untuk memuat simbol lokal menggunakan tipuan, Anda dapat menggunakan
dlopen
binary panggilan (argv[0]
).Satu-satunya persyaratan untuk ini (selain
dlopen()
,libdl
, dandlfcn.h
) adalah mengetahui argumen dan jenis fungsi.sumber