How can I use a macro for collecting variable names?
我想简化以下内容
1 2 3 4 5 6 7 8 | class A { int a; int b; int c; std::vector<int*> addrs; public: A() : addrs{ &a, &b, &c } {} }; |
,所以我没有在两个地方写字段列表,即
1 2 3 4 5 6 7 8 | class A { VAR_DECL(a); VAR_DECL(b); VAR_DECL(c); std::vector<int*> addrs; public: A() : addrs{ VAR_ADDRESSES } {} }; |
对于上下文,这旨在实现某种属性自省系统。
您可以使用Boost预处理程序来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #define VARIABLES (a)(b)(c) #define DECLARE_MEMBER(maR, maType, maId) \\ maType maId; #define TAKE_ADDRESS(maR, maUnused, maIndex, maId) \\ BOOST_PP_COMMA_IF(maIndex) & maId class A { BOOST_PP_SEQ_FOR_EACH(DECLARE_MEMBER, int, VARIABLES) std::vector<int*> addrs; public: A() : addrs { BOOST_PP_SEQ_FOR_EACH_I(TAKE_ADDRESS, %%, VARIABLES) } {} }; // Now you can clean up: #undef DECLARE_MEMBER #undef TAKE_ADDRESS // In case you no longer need the list, also: #undef VARIABLES |
我通常不回答"不要这样做,您真的想这样做"。但是在这种情况下,问题太明显了。
您正在堆上分配内存,以获取编译时可用的信息。太恐怖了
您的实现不必要地破坏了默认的复制并移动了构造函数的行为。希望您知道这一点。我希望每个重用该代码的人都知道这一点。
我想您正在尝试实现的一种访问所有成员的通用方式。请执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class A { int a; int b; int c; public: A() {} template<class F> ForEachMember(F f) { f(a); f(b); f(c); } }; |
如果
如果这是代码中的常见模式,并且您认为重复成员名称容易出错,则可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <boost/fusion/algorithm/iteration/for_each.hpp> #include <boost/fusion/include/for_each.hpp> #include <boost/fusion/adapted/boost_tuple.hpp> #include <boost/fusion/include/boost_tuple.hpp> class A : boost::tuple<int, int, int> { template<class F> ForEachMember(F f) { boost::fusion::for_each( *this, f ); } // if necessary, write getter/setter with pretty names int& a() { return get<0>(); } }; |
您可以使用union:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class A { A() { static_assert(&u.a == &u.vars[0],"&u.a == &u.vars[0] failed"); static_assert(&u.b == &u.vars[1],"&u.b == &u.vars[1] failed"); static_assert(&u.c == &u.vars[2],"&u.c == &u.vars[2] failed"); } private: union { struct { int a; int b; int c; }; int vars[3]; } u; }; |
您可以消除地址向量并遍历成员(尽管我将其保留在此处)
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | #include <iostream> #include <tuple> #include <vector> // Dedicated function template <typename T, std::size_t I = 0, typename ...Tuple> inline typename std::enable_if<I == sizeof...(Tuple), void>::type collect_addresses(std::vector<T*>& result, std::tuple<Tuple...>&) { } template <typename T, std::size_t I = 0, typename ...Tuple> inline typename std::enable_if<I < sizeof...(Tuple), void>::type collect_addresses(std::vector<T*>& result, std::tuple<Tuple...>& tuple) { result.push_back(&std::get(tuple)); collect_addresses<T, I + 1, Tuple...>(result, tuple); } template <typename T, typename ...Tuple> inline std::vector<T*> collect_addresses(std::tuple<Tuple...>& tuple) { std::vector<T*> result; result.reserve(sizeof...(Tuple)); collect_addresses(result, tuple); return result; } // Static function [Tuple] template <typename Function, std::size_t I = 0, typename ...Tuple> inline typename std::enable_if<I == sizeof...(Tuple), void>::type invoke_tuple(const Function&, std::tuple<Tuple...>&) { } template <typename Function, std::size_t I = 0, typename ...Tuple> inline typename std::enable_if<I < sizeof...(Tuple), void>::type invoke_tuple(const Function& function, std::tuple<Tuple...>& tuple) { function(std::get(tuple)); invoke_tuple<Function, I + 1, Tuple...>(function, tuple); } // Member function [Tuple] template <typename Instance, typename Function, std::size_t I = 0, typename ...Tuple> inline typename std::enable_if<I == sizeof...(Tuple), void>::type invoke_tuple(Instance&, const Function&, std::tuple<Tuple...>&) { } template <typename Instance, typename Function, std::size_t I = 0, typename ...Tuple> inline typename std::enable_if<I < sizeof...(Tuple), void>::type invoke_tuple(Instance& instance, const Function& function, std::tuple<Tuple...>& tuple) { (instance.*function)(std::get(tuple)); invoke_tuple<Instance, Function, I + 1, Tuple...>(instance, function, tuple); } // Static function [Variadic Template] template <typename Function> inline void invoke(const Function&) { } template <typename Function, typename T, typename ...Args> inline void invoke(const Function& function, T& value, Args&... args) { function(value); invoke(function, args...); } // Member function [Variadic Template] template <typename Instance, typename Function> inline void invoke(Instance&, const Function&) { } template <typename Instance, typename Function, typename T, typename ...Args> inline void invoke(Instance& instance, const Function& function, T& value, Args&... args) { (instance.*function)(value); invoke(instance, function, args...); } class A { // public in this test public: std::tuple<int, int, int> params; std::vector<int*> addrs; A() : addrs(collect_addresses<int>(params)) {} }; class B { private: typedef std::tuple<int, int, int> Params; // public in this test public: Params params; std::vector<int*> addrs; B() { addrs.reserve(std::tuple_size<Params>::value); invoke_tuple([this](int& i) { addrs.push_back(&i); }, params); } }; class C { // public in this test public: int a; int b; int c; std::vector<int*> addrs; C() { addrs.reserve(3); invoke([this](int& i) { addrs.push_back(&i); }, a, b, c); } }; int main(){ A a; for(int* p: a.addrs) std::cout << (const void*)p << std::endl; B b; for(int* p: b.addrs) std::cout << (const void*)p << std::endl; C c; for(int* p: c.addrs) std::cout << (const void*)p << std::endl; } |