├── .gitignore ├── include └── Reflectable │ ├── reflectable.h │ ├── for_each.h │ └── tagged_tuple.h ├── README.md ├── Reflectable.cbp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | obj/* 3 | *.layout 4 | *.depend -------------------------------------------------------------------------------- /include/Reflectable/reflectable.h: -------------------------------------------------------------------------------- 1 | #ifndef REFLECTABLE_REFLECTABLE_H_INCLUDED 2 | #define REFLECTABLE_REFLECTABLE_H_INCLUDED 3 | 4 | #include "Reflectable/tagged_tuple.h" 5 | #include "Reflectable/for_each.h" 6 | 7 | template 8 | class Reflectable : public tagged_tuple 9 | { 10 | public: 11 | template 12 | void iterate(const FuncT& f) 13 | { 14 | for_each(*this, f); 15 | } 16 | }; 17 | 18 | #endif // REFLECTABLE_REFLECTABLE_H_INCLUDED 19 | -------------------------------------------------------------------------------- /include/Reflectable/for_each.h: -------------------------------------------------------------------------------- 1 | #ifndef REFLECTABLE_FOR_EACH_H_INCLUDED 2 | #define REFLECTABLE_FOR_EACH_H_INCLUDED 3 | 4 | #include 5 | 6 | // ************************************************************************************************ 7 | // Code stolen from: http://stackoverflow.com/a/6894436 8 | 9 | template 10 | inline typename std::enable_if::type 11 | for_each(std::tuple &, FuncT) // Unused arguments are given no names. 12 | { 13 | } 14 | 15 | template 16 | inline typename std::enable_if::type 17 | for_each(std::tuple& t, FuncT f) 18 | { 19 | f(std::get(t)); 20 | for_each(t, f); 21 | } 22 | 23 | #endif // REFLECTABLE_FOR_EACH_H_INCLUDED 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reflectable # 2 | 3 | A C++11 header only library built from code stolen from around the internet to allow compile-time reflection. 4 | 5 | This whole thing is build on std::tuple. 6 | 7 | ### Much Thanks ### 8 | 9 | Much thanks to the template wizards who really wrote this code. All I did was steal their code and glue it together :) 10 | 11 | [Iterating through a std::tuple](http://stackoverflow.com/a/6894436 "Iterating through a std::tuple") 12 | 13 | [Tagged tuples (The real heart and soul)](http://stackoverflow.com/a/13066078 "Tagged tuples (The real heart and soul)") 14 | 15 | ### Limitations ### 16 | 17 | Member variable names use structs as tags for the compiler. This means that no other symbols can conflict with the variable names in your reflectable objects, which sucks. You can, however, reuse variable names across multiple reflectable objects. 18 | 19 | ### Benchmarks ### 20 | 21 | Without compiler optimizations 22 | 23 | Raw for loop: 0.53s 24 | Regular access: 0.597s 25 | Reflectable access: 3.782s 26 | Reflectable with reference access: 0.559s 27 | 28 | With compiler optimizations (-O) 29 | 30 | Raw for loop: 0.084s 31 | Regular access: 0.086s 32 | Reflectable access: 0.084s 33 | Reflectable with reference access: 0.104s 34 | 35 | With compiler optimizations (-O1) 36 | 37 | Raw for loop: 0.085s 38 | Regular access: 0.085s 39 | Reflectable access: 0.085s 40 | Reflectable with reference access: 0.104s 41 | -------------------------------------------------------------------------------- /Reflectable.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 50 | 51 | -------------------------------------------------------------------------------- /include/Reflectable/tagged_tuple.h: -------------------------------------------------------------------------------- 1 | #ifndef REFLECTABLE_TAGGED_TUPLE_H_INCLUDED 2 | #define REFLECTABLE_TAGGED_TUPLE_H_INCLUDED 3 | 4 | #include 5 | 6 | // ************************************************************************************************ 7 | // Code stolen from: http://stackoverflow.com/a/13066078 8 | 9 | template struct typelist { 10 | template using prepend = typelist; 11 | }; 12 | 13 | template struct index; 14 | template struct index: 15 | std::integral_constant {}; 16 | template struct index: 17 | std::integral_constant::value + 1> {}; 18 | 19 | template struct nth_impl; 20 | template struct nth_impl<0, T, Ts...> { 21 | using type = T; }; 22 | template struct nth_impl { 23 | using type = typename nth_impl::type; }; 24 | template using nth = typename nth_impl::type; 25 | 26 | template struct extract_impl; 27 | template 28 | struct extract_impl: extract_impl {}; 29 | template 30 | struct extract_impl { using types = typename 31 | extract_impl::types::template prepend; }; 32 | template struct extract_impl { 33 | using types = typelist<>; }; 34 | template using extract = typename 35 | extract_impl::types; 36 | 37 | template struct tt_impl; 38 | template 39 | struct tt_impl, typelist>: 40 | public std::tuple { 41 | template tt_impl(Args &&...args): 42 | std::tuple(std::forward(args)...) {} 43 | template nth::value, Ts...>& get() { 44 | return std::get::value>(*this); } 45 | }; 46 | template struct tagged_tuple: 47 | tt_impl, extract<2, 1, Ts...>> { 48 | template tagged_tuple(Args &&...args): 49 | tt_impl, extract<2, 1, Ts...>>( 50 | std::forward(args)...) {} 51 | }; 52 | 53 | #endif // REFLECTABLE_TAGGED_TUPLE_H_INCLUDED 54 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Reflectable/reflectable.h" 7 | 8 | struct Foo 9 | { 10 | std::string str; 11 | int i; 12 | }; 13 | 14 | std::ostream& operator<<(std::ostream& left, const Foo& right) 15 | { 16 | return left << "str: " << right.str << ", " << "i: " << right.i; 17 | } 18 | 19 | /// \brief A super basic printer 20 | class SamplePrinter 21 | { 22 | public: 23 | /// \brief Int serialization 24 | void operator () (int x) 25 | { 26 | std::cout << "int: " << x << std::endl; 27 | } 28 | 29 | /// \brief Float serialization 30 | void operator () (float x) 31 | { 32 | std::cout << "float: " << x << std::endl; 33 | } 34 | 35 | /// \brief Double serialization 36 | void operator () (double x) 37 | { 38 | std::cout << "double: " << x << std::endl; 39 | } 40 | 41 | /// \brief String serialization 42 | void operator () (const std::string& x) 43 | { 44 | std::cout << "string: " << x << std::endl; 45 | } 46 | 47 | /// \brief The generic case 48 | template 49 | void operator () (const X& x) 50 | { 51 | std::cout << "other: " << x << std::endl; 52 | } 53 | 54 | private: 55 | }; 56 | 57 | struct Test : public Reflectable 60 | { 61 | }; 62 | 63 | struct TestReferences : public Reflectable 66 | { 67 | TestReferences() : name(get()), health(get()), foo(get()) 68 | { 69 | } 70 | 71 | std::string& name; 72 | int& health; 73 | Foo& foo; 74 | }; 75 | 76 | struct TestNormal 77 | { 78 | std::string name; 79 | int health; 80 | Foo foo; 81 | }; 82 | 83 | int main() 84 | { 85 | Test test; 86 | test.get() = "bob"; 87 | test.get() = 42; 88 | test.get().str = "hello"; 89 | test.get().i = 24; 90 | 91 | test.iterate(SamplePrinter()); 92 | 93 | std::cout << "\n\nBenchmarks:\n\n"; 94 | 95 | clock_t time; 96 | 97 | // ****************************************** 98 | // Raw for loop 99 | 100 | time = clock(); 101 | for (int i = 0; i < 100000000; i++); 102 | time = clock()-time; 103 | std::cout << "Raw for loop: " << static_cast(time)/CLOCKS_PER_SEC << "s\n"; 104 | 105 | // ****************************************** 106 | // Regular benchmark 107 | 108 | TestNormal testNormal; 109 | 110 | time = clock(); 111 | for (int i = 0; i < 100000000; i++) 112 | { 113 | testNormal.foo.i = i; 114 | } 115 | time = clock()-time; 116 | std::cout << "Regular access: " << static_cast(time)/CLOCKS_PER_SEC << "s\n"; 117 | 118 | // ****************************************** 119 | // Reflectable benchmark 120 | 121 | time = clock(); 122 | for (int i = 0; i < 100000000; i++) 123 | { 124 | test.get().i = i; 125 | } 126 | time = clock()-time; 127 | std::cout << "Reflectable access: " << static_cast(time)/CLOCKS_PER_SEC << "s\n"; 128 | 129 | // ****************************************** 130 | // Reflectable with reference benchmark 131 | 132 | TestReferences testRef; 133 | 134 | time = clock(); 135 | for (int i = 0; i < 100000000; i++) 136 | { 137 | testRef.foo.i = i; 138 | } 139 | time = clock()-time; 140 | std::cout << "Reflectable with reference access: " << static_cast(time)/CLOCKS_PER_SEC << "s\n"; 141 | 142 | return 0; 143 | } 144 | --------------------------------------------------------------------------------