原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <iostream> #include <string> struct Test { int index; std::string name; void printInfo() const { std::cout << "index: " << index << ", name: " << name << "\n"; } }; int main() { Test test; test.index = 1; test.name = "test_1"; test.printInfo(); auto index_addr = &Test::index; auto name_addr = &Test::name; auto fun_print_addr = &Test::printInfo; test.*index_addr = 2; test.*name_addr = "test_2"; (test.*fun_print_addr)(); return 0; };
|
透過上面的index_addr
,name_addr
,fun_print_addr
等,可以對object進行操作
而反射主要分成兩部分
- Metadata generation
和C++ object有關的information就叫做metadata,如上面的例子,這邊的困難點是如何減少工作量
- Metadata Reflection
既然有了Metadata,如何跟現實使用上連結起來
雖然目前的官方標準還沒出來,不過現在有兩大流派
手工打造
什麼辦不到的事情,用Marco就好了
以Boost Describe舉例
1 2 3 4 5 6
| struct X { int m1; int m2; }; BOOST_DESCRIBE_STRUCT(X, (), (m1, m2))
|
其他Macro Based的方案也差不多,就是另外定義一個Macro,自動生成類似上面的Metadata
不過這邊的問題就是
- 你要同時維護兩份資料的一致性
- Macro滿天飛
- 修改困難 (因為都是Marco的黑魔法,要新增功能就得對Marco動刀)
libclang
另外一派就是借助libclang來動手生成,透過Parse C++ AST來生成需要的API
舉例說明
1 2 3 4 5 6 7 8
| class MyClass { public: int field = 0; static int static_field; void method(); static void static_method(); };
|
生成的Metadata可以這麼使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| reflang::Class<MyClass> metadata; MyClass c;
reflang::Reference ref = metadata.GetField(c, "field"); ref.GetT<int>() = 10;
ref = metadata.GetStaticField("static_field") ref.GetT<int>() = 10;
auto methods = metadata.GetMethod("method"); (*methods[0])(c);
auto methods = metadata.GetStaticMethod("static_method"); (*methods[0])();
|
這個方案的問題在於
- 要有libclang才能用
- 構建的時候會多一個步驟,必須掃描所有的檔案,生成需要的header/sources,修改Makefile/CMakeLists.txt來調整編譯流程
Reflection API in the future
雖然現有的Reflection library多的跟山一樣,不過眾口難調,有些是針對特定用途設計的,無法涵蓋其他方面的使用,有些功能完整,但是難用
於是乎就有人想要對語法方面下手,成為C++ Standard中的一部分
1 2 3 4 5 6 7 8
| template <class T> void print_type() { std::cout << "void " << get_name_v<reflexpr(print_type<T>)> << "() [with T = " << get_display_name_v<reflexpr(T)> << "]" << std::endl; }
|
reflexpr和decltype一樣是type-based,所以可以套用到type based metaprogramming中
不過會不會成為標準是另外一回事了
跟Network Library一樣,成為標準之前先用成熟的方案解決
Reference