├── .gitignore ├── CMakeLists.txt ├── README.md ├── example_complex.cpp ├── example_jsoncpp.cpp ├── example_pybind.cpp ├── foreachgen.py ├── reflect.hpp └── reflect_json.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | a.out 2 | *.o 3 | build 4 | .~* 5 | GNUmakefile 6 | r000*/ 7 | .wip/ 8 | *.exe 9 | .cache 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | set(CMAKE_CXX_STANDARD 14) 4 | 5 | project(main) 6 | 7 | add_compile_options(-Wall -Wextra -Werror=return-type) 8 | if (MSVC) 9 | add_compile_options(/Zc:preprocessor) 10 | endif() 11 | 12 | file(GLOB sources CONFIGURE_DEPENDS "*.cpp") 13 | foreach(source IN LISTS sources) 14 | get_filename_component(name ${source} NAME_WE) 15 | add_executable(${name} ${source}) 16 | target_link_libraries(${name} PRIVATE jsoncpp) 17 | target_include_directories(${name} PRIVATE /usr/include/python3.12) 18 | # find_package(pybind11 REQUIRED) 19 | # target_link_libraries(${name} PRIVATE pybind11) 20 | endforeach() 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reflect.hpp 2 | 3 | ```cpp 4 | #include 5 | #include "reflect.hpp" 6 | #include "reflect_json.hpp" 7 | 8 | struct Address { 9 | std::string country; 10 | std::string province; 11 | std::string city; 12 | 13 | void show() { 14 | std::cout << "Country: " << country << '\n'; 15 | std::cout << "Province: " << province << '\n'; 16 | std::cout << "City: " << city << '\n'; 17 | } 18 | 19 | std::string to_str() const { 20 | return country + " " + province + " " + city; 21 | } 22 | 23 | static void test() { 24 | std::cout << "static function test\n"; 25 | } 26 | 27 | REFLECT(country, province, city, show, to_str, test); 28 | }; 29 | 30 | struct Student { 31 | std::string name; 32 | int age; 33 | Address addr; 34 | 35 | REFLECT(name, age, addr); 36 | }; 37 | 38 | 39 | int main() { 40 | Student stu = { 41 | .name = "Peng", 42 | .age = 23, 43 | .addr = { 44 | .country = "China", 45 | .province = "Shanghai", 46 | .city = "Shanghai", 47 | } 48 | }; 49 | 50 | std::string binary = reflect_json::serialize(stu); 51 | std::cout << binary << '\n'; 52 | auto stuDes = reflect_json::deserialize(binary); 53 | 54 | std::cout << stuDes.name << '\n'; 55 | std::cout << stuDes.age << '\n'; 56 | std::cout << stuDes.addr.country << '\n'; 57 | std::cout << stuDes.addr.province << '\n'; 58 | std::cout << stuDes.addr.city << '\n'; 59 | 60 | auto vec = reflect_json::deserialize>(R"json([1, 2, 3])json"); 61 | std::cout << vec.at(0) << '\n'; 62 | std::cout << vec.at(1) << '\n'; 63 | std::cout << vec.at(2) << '\n'; 64 | 65 | return 0; 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /example_complex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "reflect.hpp" 8 | 9 | 10 | struct Student { 11 | std::string name; 12 | int age; 13 | int sex; 14 | 15 | void speak(std::string lang, bool newline) const { 16 | if (lang == "cn") { 17 | std::cout << "你好!我是" << name << ",今年" << age << "岁,是" << (sex == 1 ? "男" : "女") << "生。"; 18 | } else { 19 | std::cout << "Hello! I am " << name << ", " << age << " years old, a " << (sex == 1 ? "boy" : "girl") << "."; 20 | } 21 | if (newline) { 22 | std::cout << '\n'; 23 | } 24 | } 25 | 26 | REFLECT(name, age, sex, speak); // 就地定义 27 | }; 28 | 29 | 30 | struct Student2 { 31 | std::string name; 32 | int age; 33 | int sex; 34 | }; 35 | REFLECT_TYPE(Student2, name, age, sex); // 如果不能修改类的定义 36 | 37 | 38 | template 39 | struct Baby { 40 | N name; 41 | T hungry; 42 | }; 43 | REFLECT_TYPE_TEMPLATED(((Baby), class T, class N), name, hungry); // 如果不能修改类的定义,且类是模板 44 | 45 | template 46 | std::string jsonSerialize(T &object) { 47 | Json::Value root; 48 | reflect::foreach_member(object, [&](const char *key, auto &value) { 49 | root[key] = value; 50 | }); 51 | Json::StreamWriterBuilder builder; 52 | builder["indentation"] = ""; 53 | std::unique_ptr writer(builder.newStreamWriter()); 54 | std::ostringstream os; 55 | writer->write(root, &os); 56 | return os.str(); 57 | } 58 | 59 | template 60 | T jsonDeserialize(std::string const &json) { 61 | Json::Value root; 62 | Json::Reader reader; 63 | reader.parse(json, root); 64 | T object; 65 | reflect::foreach_member(object, [&](const char *key, auto &value) { 66 | value = root[key].as>(); 67 | }); 68 | return object; 69 | } 70 | 71 | 72 | int main() { 73 | Student stu = { 74 | .name = "Peng", 75 | .age = 23, 76 | .sex = 1, 77 | }; 78 | Student2 stu2 = { 79 | .name = "Sir", 80 | .age = 23, 81 | .sex = 1, 82 | }; 83 | Baby baby = { 84 | .name = "Tom", 85 | .hungry = 1, 86 | }; 87 | Baby baby2 = { 88 | .name = "Jerry", 89 | .hungry = 2.0f, 90 | }; 91 | 92 | std::string bin = jsonSerialize(stu); 93 | std::cout << bin << '\n'; 94 | auto stuDes = jsonDeserialize(bin); 95 | std::cout << stuDes.name << '\n'; 96 | std::cout << stuDes.age << '\n'; 97 | std::cout << stuDes.sex << '\n'; 98 | 99 | std::cout << std::boolalpha; 100 | std::cout << reflect::get_member(stu, "name") << '\n'; 101 | std::cout << reflect::get_member(stu, "age") << '\n'; 102 | std::cout << reflect::get_member(stu, "sex") << '\n'; 103 | std::cout << reflect::has_member("sex") << '\n'; 104 | std::cout << reflect::has_member("sey") << '\n'; 105 | std::cout << reflect::is_member_type("sex") << '\n'; 106 | std::cout << reflect::is_member_type("sex") << '\n'; 107 | std::cout << reflect::is_member_type("sex") << '\n'; 108 | // reflect::get_function(stu, "speak")("cn", true); 109 | 110 | bin = jsonSerialize(stu); 111 | std::cout << bin << '\n'; 112 | bin = jsonSerialize(baby); 113 | std::cout << bin << '\n'; 114 | bin = jsonSerialize(baby2); 115 | std::cout << bin << '\n'; 116 | 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /example_jsoncpp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "reflect.hpp" 3 | #include "reflect_json.hpp" 4 | 5 | struct Address { 6 | std::string country; 7 | std::string province; 8 | std::string city; 9 | 10 | void show() { 11 | std::cout << "Country: " << country << '\n'; 12 | std::cout << "Province: " << province << '\n'; 13 | std::cout << "City: " << city << '\n'; 14 | } 15 | 16 | std::string to_str() const { 17 | return country + " " + province + " " + city; 18 | } 19 | 20 | static void test() { 21 | std::cout << "static function test\n"; 22 | } 23 | 24 | REFLECT(country, province, city, show, to_str, test); 25 | }; 26 | 27 | struct Student { 28 | std::string name; 29 | int age; 30 | Address addr; 31 | 32 | REFLECT(name, age, addr); 33 | }; 34 | 35 | 36 | int main() { 37 | Student stu = { 38 | .name = "Peng", 39 | .age = 23, 40 | .addr = { 41 | .country = "China", 42 | .province = "Shanghai", 43 | .city = "Shanghai", 44 | } 45 | }; 46 | 47 | std::string binary = reflect_json::serialize(stu); 48 | std::cout << binary << '\n'; 49 | auto stuDes = reflect_json::deserialize(binary); 50 | 51 | std::cout << stuDes.name << '\n'; 52 | std::cout << stuDes.age << '\n'; 53 | std::cout << stuDes.addr.country << '\n'; 54 | std::cout << stuDes.addr.province << '\n'; 55 | std::cout << stuDes.addr.city << '\n'; 56 | 57 | auto vec = reflect_json::deserialize>(R"json([1, 2, 3])json"); 58 | std::cout << vec.at(0) << '\n'; 59 | std::cout << vec.at(1) << '\n'; 60 | std::cout << vec.at(2) << '\n'; 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /example_pybind.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "reflect.hpp" 4 | 5 | struct Address { 6 | std::string country; 7 | std::string province; 8 | std::string city; 9 | 10 | void show() { 11 | std::cout << "Country: " << country << '\n'; 12 | std::cout << "Province: " << province << '\n'; 13 | std::cout << "City: " << city << '\n'; 14 | } 15 | 16 | std::string to_str() const { 17 | return country + " " + province + " " + city; 18 | } 19 | 20 | static void test() { 21 | std::cout << "static function test\n"; 22 | } 23 | 24 | REFLECT(country, province, city, show, to_str, test); 25 | }; 26 | 27 | struct Student { 28 | std::string name; 29 | int age; 30 | Address addr; 31 | 32 | REFLECT(name, age, addr); 33 | }; 34 | 35 | template 36 | pybind11::class_ autodef(pybind11::module &m, const char *clsname) { 37 | pybind11::class_
c(m, clsname); 38 | reflect::foreach_member_ptr
([&] (const char *name, auto member) { 39 | c.def(name, member); 40 | }); 41 | return c; 42 | } 43 | 44 | PYBIND11_MODULE(pyreflect, m) { 45 | autodef
(m, "Address"); 46 | autodef(m, "Student"); 47 | } 48 | -------------------------------------------------------------------------------- /foreachgen.py: -------------------------------------------------------------------------------- 1 | # this python scripts generates: 2 | #define REFLECT__PP_FOREACH_1(f, _1) f(_1) 3 | #define REFLECT__PP_FOREACH_2(f, _1, _2) f(_1) f(_2) 4 | #define REFLECT__PP_FOREACH_3(f, _1, _2, _3) f(_1) f(_2) f(_3) 5 | #define REFLECT__PP_FOREACH_4(f, _1, _2, _3, _4) f(_1) f(_2) f(_3) f(_4) 6 | #define REFLECT__PP_FOREACH_5(f, _1, _2, _3, _4, _5) f(_1) f(_2) f(_3) f(_4) f(_5) 7 | # ... 8 | #define REFLECT__PP_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...) N 9 | #define REFLECT__PP_NARGS(...) REFLECT__PP_NARGS_IMPL(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 10 | 11 | import sys 12 | 13 | n = int(sys.argv[1]) 14 | for i in range(1, n+1): 15 | print("#define REFLECT__PP_FOREACH_{0}(f, {1}) ".format(i, ", ".join(["_"+str(j) for j in range(1, i+1)])), end="") 16 | print(" ".join(["f(_{0})".format(j) for j in range(1, i+1)])) 17 | 18 | print("#define REFLECT__PP_NARGS_IMPL({0}, N, ...) N".format(", ".join(["_"+str(j) for j in range(1, n+1)]))) 19 | print("#define REFLECT__PP_NARGS(...) REFLECT__PP_NARGS_IMPL(__VA_ARGS__, {0})".format(", ".join([str(j) for j in range(n, 0, -1)]))) 20 | -------------------------------------------------------------------------------- /reflect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | // #include 8 | 9 | // easy-to-use static reflection with C++14 and macros 10 | namespace reflect { 11 | 12 | // BEGIN GENERATED BY foreachgen.py 13 | #define REFLECT__PP_FOREACH_1(f, _1) f(_1) 14 | #define REFLECT__PP_FOREACH_2(f, _1, _2) f(_1) f(_2) 15 | #define REFLECT__PP_FOREACH_3(f, _1, _2, _3) f(_1) f(_2) f(_3) 16 | #define REFLECT__PP_FOREACH_4(f, _1, _2, _3, _4) f(_1) f(_2) f(_3) f(_4) 17 | #define REFLECT__PP_FOREACH_5(f, _1, _2, _3, _4, _5) f(_1) f(_2) f(_3) f(_4) f(_5) 18 | #define REFLECT__PP_FOREACH_6(f, _1, _2, _3, _4, _5, _6) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) 19 | #define REFLECT__PP_FOREACH_7(f, _1, _2, _3, _4, _5, _6, _7) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) 20 | #define REFLECT__PP_FOREACH_8(f, _1, _2, _3, _4, _5, _6, _7, _8) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) 21 | #define REFLECT__PP_FOREACH_9(f, _1, _2, _3, _4, _5, _6, _7, _8, _9) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) 22 | #define REFLECT__PP_FOREACH_10(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) 23 | #define REFLECT__PP_FOREACH_11(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) 24 | #define REFLECT__PP_FOREACH_12(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) 25 | #define REFLECT__PP_FOREACH_13(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) 26 | #define REFLECT__PP_FOREACH_14(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) 27 | #define REFLECT__PP_FOREACH_15(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) 28 | #define REFLECT__PP_FOREACH_16(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) 29 | #define REFLECT__PP_FOREACH_17(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) 30 | #define REFLECT__PP_FOREACH_18(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) 31 | #define REFLECT__PP_FOREACH_19(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) 32 | #define REFLECT__PP_FOREACH_20(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) 33 | #define REFLECT__PP_FOREACH_21(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) 34 | #define REFLECT__PP_FOREACH_22(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) 35 | #define REFLECT__PP_FOREACH_23(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) 36 | #define REFLECT__PP_FOREACH_24(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) 37 | #define REFLECT__PP_FOREACH_25(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) f(_25) 38 | #define REFLECT__PP_FOREACH_26(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) f(_25) f(_26) 39 | #define REFLECT__PP_FOREACH_27(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) f(_25) f(_26) f(_27) 40 | #define REFLECT__PP_FOREACH_28(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) f(_25) f(_26) f(_27) f(_28) 41 | #define REFLECT__PP_FOREACH_29(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) f(_25) f(_26) f(_27) f(_28) f(_29) 42 | #define REFLECT__PP_FOREACH_30(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) f(_25) f(_26) f(_27) f(_28) f(_29) f(_30) 43 | #define REFLECT__PP_FOREACH_31(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) f(_25) f(_26) f(_27) f(_28) f(_29) f(_30) f(_31) 44 | #define REFLECT__PP_FOREACH_32(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32) f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20) f(_21) f(_22) f(_23) f(_24) f(_25) f(_26) f(_27) f(_28) f(_29) f(_30) f(_31) f(_32) 45 | #define REFLECT__PP_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, N, ...) N 46 | #define REFLECT__PP_NARGS(...) REFLECT__PP_NARGS_IMPL(__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 47 | // END GENERATED BY foreachgen.py 48 | 49 | #define REFLECT__PP_EXPAND_2(...) __VA_ARGS__ 50 | #define REFLECT__PP_EXPAND(...) REFLECT__PP_EXPAND_2(__VA_ARGS__) 51 | #define REFLECT__PP_CONCAT_2(x, y) x##y 52 | #define REFLECT__PP_CONCAT(x, y) REFLECT__PP_CONCAT_2(x, y) 53 | #define REFLECT__PP_FOREACH(f, ...) REFLECT__PP_EXPAND(REFLECT__PP_CONCAT(REFLECT__PP_FOREACH_, REFLECT__PP_NARGS(__VA_ARGS__))(f, __VA_ARGS__)) 54 | 55 | template 56 | inline constexpr auto _has_member_test(int) -> decltype(T::template foreach_member_ptr(nullptr), true) { 57 | return true; 58 | } 59 | 60 | template 61 | inline constexpr bool _has_member_test(...) { 62 | return false; 63 | } 64 | 65 | template 66 | struct reflect_trait { 67 | static constexpr bool has_member() { 68 | return reflect::_has_member_test(0); 69 | } 70 | 71 | template 72 | static constexpr void foreach_member_ptr(Func &&func) { 73 | T::template foreach_member_ptr(func); 74 | } 75 | }; 76 | 77 | #define REFLECT__TYPE_PER_MEMBER_PTR(x) \ 78 | func(#x, &This::x); 79 | 80 | #define REFLECT_TYPE(Type, ...) \ 81 | template <> \ 82 | struct reflect::reflect_trait { \ 83 | using This = Type; \ 84 | static constexpr bool has_member() { return true; }; \ 85 | template \ 86 | static constexpr void foreach_member_ptr(Func &&func) { \ 87 | REFLECT__PP_FOREACH(REFLECT__TYPE_PER_MEMBER_PTR, __VA_ARGS__) \ 88 | } \ 89 | }; 90 | 91 | #define REFLECT__TYPE_TEMPLATED_FIRST(x, ...) REFLECT__PP_EXPAND(REFLECT__PP_EXPAND x) 92 | #define REFLECT__TYPE_TEMPLATED_REST(x, ...) __VA_ARGS__ 93 | 94 | #define REFLECT_TYPE_TEMPLATED(Type, ...) \ 95 | template \ 96 | struct reflect::reflect_trait { \ 97 | using This = REFLECT__PP_EXPAND(REFLECT__TYPE_TEMPLATED_FIRST Type); \ 98 | static constexpr bool has_member() { return true; }; \ 99 | template \ 100 | static constexpr void foreach_member_ptr(Func &&func) { \ 101 | REFLECT__PP_FOREACH(REFLECT__TYPE_PER_MEMBER_PTR, __VA_ARGS__) \ 102 | } \ 103 | }; 104 | 105 | #define REFLECT__PER_MEMBER(x) \ 106 | func(#x, x); 107 | 108 | #define REFLECT__PER_MEMBER_PTR(x) \ 109 | func(#x, &This::x); 110 | 111 | #define REFLECT(...) \ 112 | template \ 113 | static constexpr void foreach_member_ptr(Func &&func) { \ 114 | REFLECT__PP_FOREACH(REFLECT__PER_MEMBER_PTR, __VA_ARGS__) \ 115 | } 116 | 117 | enum class member_kind { 118 | member_variable, 119 | member_function, 120 | static_variable, 121 | static_function, 122 | }; 123 | 124 | template 125 | struct get_member_kind; 126 | 127 | template 128 | struct get_member_kind { 129 | static constexpr member_kind value = member_kind::member_variable; 130 | }; 131 | 132 | template 133 | struct get_member_kind { 134 | static constexpr member_kind value = member_kind::static_variable; 135 | }; 136 | 137 | template 138 | struct get_member_kind { 139 | static constexpr member_kind value = member_kind::member_function; 140 | }; 141 | 142 | template 143 | struct get_member_kind { 144 | static constexpr member_kind value = member_kind::member_function; 145 | }; 146 | 147 | template 148 | struct get_member_kind { 149 | static constexpr member_kind value = member_kind::member_function; 150 | }; 151 | 152 | template 153 | struct get_member_kind { 154 | static constexpr member_kind value = member_kind::member_function; 155 | }; 156 | 157 | template 158 | struct get_member_kind { 159 | static constexpr member_kind value = member_kind::member_function; 160 | }; 161 | 162 | template 163 | struct get_member_kind { 164 | static constexpr member_kind value = member_kind::member_function; 165 | }; 166 | 167 | #if __cpp_noexcept_function_type 168 | template 169 | struct get_member_kind { 170 | static constexpr member_kind value = member_kind::member_function; 171 | }; 172 | 173 | template 174 | struct get_member_kind { 175 | static constexpr member_kind value = member_kind::member_function; 176 | }; 177 | 178 | template 179 | struct get_member_kind { 180 | static constexpr member_kind value = member_kind::member_function; 181 | }; 182 | 183 | template 184 | struct get_member_kind { 185 | static constexpr member_kind value = member_kind::member_function; 186 | }; 187 | 188 | template 189 | struct get_member_kind { 190 | static constexpr member_kind value = member_kind::member_function; 191 | }; 192 | 193 | template 194 | struct get_member_kind { 195 | static constexpr member_kind value = member_kind::member_function; 196 | }; 197 | #endif 198 | 199 | template 200 | struct get_member_kind { 201 | static constexpr member_kind value = member_kind::static_function; 202 | }; 203 | 204 | #if __cpp_noexcept_function_type 205 | template 206 | struct get_member_kind { 207 | static constexpr member_kind value = member_kind::static_function; 208 | }; 209 | #endif 210 | 211 | template 212 | struct _foreach_visitor { 213 | T &&object; 214 | Func &&func; 215 | 216 | template 217 | constexpr std::enable_if_t::value == member_kind::member_variable> 218 | operator()(const char *name, U member) const { 219 | func(name, object.*member); 220 | } 221 | 222 | constexpr void operator()(...) const {} 223 | }; 224 | 225 | template 226 | using _rmcvref_t = std::remove_cv_t>; 227 | 228 | template 229 | constexpr void foreach_member(T &&object, Func &&func) { 230 | _foreach_visitor visitor{std::forward(object), std::forward(func)}; 231 | reflect_trait<_rmcvref_t>::foreach_member_ptr(visitor); 232 | } 233 | 234 | template 235 | constexpr void foreach_member_ptr(Func &&func) { 236 | reflect_trait<_rmcvref_t>::foreach_member_ptr(func); 237 | } 238 | 239 | template 240 | [[nodiscard]] constexpr bool has_member() { 241 | return reflect_trait<_rmcvref_t>::has_member(); 242 | } 243 | 244 | template 245 | [[nodiscard]] constexpr MemberType *try_get_member(T &&object, std::string const &name) { 246 | void const *ret = nullptr; 247 | reflect::foreach_member(object, [&] (const char *that_name, auto &member) { 248 | if (name == that_name && std::is_same<_rmcvref_t, _rmcvref_t>::value) { 249 | ret = &member; 250 | } 251 | }); 252 | return static_cast(const_cast(ret)); 253 | } 254 | 255 | template 256 | [[nodiscard]] constexpr MemberType &get_member(T &&object, std::string const &name) { 257 | MemberType *ret = try_get_member(std::forward(object), name); 258 | if (!ret) { 259 | throw std::invalid_argument("member name or type wrong"); 260 | } 261 | return *ret; 262 | } 263 | 264 | template 265 | [[nodiscard]] constexpr bool has_member(std::string const &name) { 266 | bool ret = false; 267 | reflect::foreach_member_ptr([&] (const char *that_name, auto) { 268 | if (name == that_name) { 269 | ret = true; 270 | } 271 | }); 272 | return ret; 273 | } 274 | 275 | template 276 | [[nodiscard]] constexpr bool is_member_kind(std::string const &name, member_kind kind) { 277 | bool ret = false; 278 | reflect::foreach_member_ptr([&] (const char *that_name, auto member) { 279 | if (name == that_name && get_member_kind::value == kind) { 280 | ret = true; 281 | } 282 | }); 283 | return ret; 284 | } 285 | 286 | template 287 | [[nodiscard]] constexpr bool is_member_ptr_type(std::string const &name) { 288 | bool ret = false; 289 | reflect::foreach_member_ptr([&] (const char *that_name, auto member) { 290 | if (name == that_name && std::is_same::value) { 291 | ret = true; 292 | } 293 | }); 294 | return ret; 295 | } 296 | 297 | template 298 | [[nodiscard]] constexpr bool is_member_type(std::string const &name) { 299 | bool ret = false; 300 | reflect::foreach_member_ptr([&] (const char *that_name, auto member) { 301 | if (name == that_name && std::is_same::value) { 302 | ret = true; 303 | } 304 | }); 305 | return ret; 306 | } 307 | 308 | // template 309 | // struct _get_function_static_visitor; 310 | // 311 | // template 312 | // struct _get_function_static_visitor { 313 | // std::string const &name; 314 | // std::function ret; 315 | // 316 | // template 317 | // std::enable_if_t::value == member_kind::static_function 318 | // && std::is_convertible()(std::declval()...)), RetType>::value> 319 | // constexpr operator()(const char *that_name, U member) const { 320 | // if (name == that_name) { 321 | // ret = member; 322 | // } 323 | // } 324 | // 325 | // constexpr void operator()(...) const {} 326 | // }; 327 | // 328 | // template 329 | // struct _get_function_member_visitor; 330 | // 331 | // template 332 | // struct _get_function_member_visitor { 333 | // T &&object; 334 | // std::string const &name; 335 | // std::function ret; 336 | // 337 | // template 338 | // std::enable_if_t::value == member_kind::member_function 339 | // && std::is_convertible())(std::declval()...)), RetType>::value> 340 | // constexpr operator()(const char *that_name, U member) const { 341 | // if (name == that_name) { 342 | // ret = [&object = std::forward(object), member] (auto &&...args) { 343 | // return (object.*member)(std::forward(args)...); 344 | // }; 345 | // } 346 | // } 347 | // 348 | // template 349 | // std::enable_if_t::value == member_kind::static_function 350 | // && std::is_convertible())(std::declval()...)), RetType>::value> 351 | // constexpr operator()(const char *that_name, U member) const { 352 | // if (name == that_name) { 353 | // ret = [object = std::forward(object), member] (auto &&...args) { 354 | // return (*member)(std::forward(args)...); 355 | // }; 356 | // } 357 | // } 358 | // 359 | // constexpr void operator()(...) const {} 360 | // }; 361 | // 362 | // template 363 | // [[nodiscard]] constexpr std::function get_static_function(std::string const &name) { 364 | // _get_function_static_visitor visitor{name, nullptr}; 365 | // reflect::foreach_member_ptr(visitor); 366 | // return visitor.ret; 367 | // } 368 | // 369 | // template 370 | // [[nodiscard]] constexpr std::function get_function(T &&object, std::string const &name) { 371 | // _get_function_member_visitor visitor{std::forward(object), name, nullptr}; 372 | // reflect::foreach_member_ptr(visitor); 373 | // return visitor.ret; 374 | // } 375 | 376 | } 377 | -------------------------------------------------------------------------------- /reflect_json.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "reflect.hpp" 9 | 10 | namespace reflect_json { 11 | 12 | inline std::string jsonToStr(Json::Value root) { 13 | Json::StreamWriterBuilder builder; 14 | builder["indentation"] = ""; 15 | std::unique_ptr writer(builder.newStreamWriter()); 16 | std::ostringstream os; 17 | writer->write(root, &os); 18 | return os.str(); 19 | } 20 | 21 | inline Json::Value strToJson(std::string const &json) { 22 | Json::Value root; 23 | Json::Reader reader; 24 | reader.parse(json, root); 25 | return root; 26 | } 27 | 28 | template 29 | struct special_traits { 30 | static constexpr bool value = false; 31 | }; 32 | 33 | template () && !special_traits::value, int> = 0> 34 | Json::Value objToJson(T const &object) { 35 | return object; 36 | } 37 | 38 | template () && special_traits::value, int> = 0> 39 | Json::Value objToJson(T const &object) { 40 | return special_traits::objToJson(object); 41 | } 42 | 43 | template (), int> = 0> 44 | Json::Value objToJson(T const &object) { 45 | Json::Value root; 46 | reflect::foreach_member(object, [&](const char *key, auto &value) { 47 | root[key] = objToJson(value); 48 | }); 49 | return root; 50 | } 51 | 52 | template () && !special_traits::value, int> = 0> 53 | T jsonToObj(Json::Value const &root) { 54 | return root.as(); 55 | } 56 | 57 | template () && special_traits::value, int> = 0> 58 | T jsonToObj(Json::Value const &root) { 59 | return special_traits::jsonToObj(root); 60 | } 61 | 62 | template (), int> = 0> 63 | T jsonToObj(Json::Value const &root) { 64 | T object; 65 | reflect::foreach_member(object, [&](const char *key, auto &value) { 66 | value = jsonToObj>(root[key]); 67 | }); 68 | return object; 69 | } 70 | 71 | template 72 | struct special_traits> { 73 | static constexpr bool value = true; 74 | 75 | static Json::Value objToJson(std::vector const &object) { 76 | Json::Value root; 77 | for (auto const &elem: object) { 78 | root.append(reflect_json::objToJson(elem)); 79 | } 80 | return root; 81 | } 82 | 83 | static std::vector jsonToObj(Json::Value const &root) { 84 | std::vector object; 85 | for (auto const &elem: root) { 86 | object.push_back(reflect_json::jsonToObj(elem)); 87 | } 88 | return object; 89 | } 90 | }; 91 | 92 | template 93 | struct special_traits> { 94 | static constexpr bool value = true; 95 | 96 | static Json::Value objToJson(std::map const &object) { 97 | Json::Value root; 98 | for (auto const &elem: object) { 99 | root[elem.first] = reflect_json::objToJson(elem.second); 100 | } 101 | return root; 102 | } 103 | 104 | static std::map jsonToObj(Json::Value const &root) { 105 | std::map object; 106 | for (auto const &key: root.getMemberNames()) { 107 | object[key] = reflect_json::jsonToObj(root[key]); 108 | } 109 | return object; 110 | } 111 | }; 112 | 113 | template 114 | std::string serialize(T const &object) { 115 | return jsonToStr(objToJson(object)); 116 | } 117 | 118 | template 119 | T deserialize(std::string const &json) { 120 | return jsonToObj(strToJson(json)); 121 | } 122 | 123 | } 124 | --------------------------------------------------------------------------------