如何使用宏来收集变量名
How can I use a macro for collecting variable names?
我想简化以下
class A {
int a;
int b;
int c;
std::vector<int*> addrs;
public:
A() : addrs{ &a, &b, &c } {}
};
这样我就不需要在两个地方写字段列表,即声明和addrs
的初始值设定项。是否有某种方法可以使用宏来收集声明并在以后使用它们。例如,
class A {
VAR_DECL(a);
VAR_DECL(b);
VAR_DECL(c);
std::vector<int*> addrs;
public:
A() : addrs{ VAR_ADDRESSES } {}
};
就上下文而言,这是为了实现某种属性内省系统。
您可以使用Boost预处理器来完成此操作。
#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
我通常不会回答"不要这样做,你真的想那样做"。但在这种情况下,问题太明显了。
-
您正在堆上为编译时可用的信息分配内存。这太可怕了。
-
您的实现不必要地破坏了默认的复制和移动构造函数行为。我希望你知道这一点。我希望每个重用该代码的人都知道这一点。
-
我想你试图实现的是访问所有成员的通用方式。执行以下操作:
class A { int a; int b; int c; public: A() {} template<class F> ForEachMember(F f) { f(a); f(b); f(c); } };
如果F::operator()
过载,这将支持不同类型的成员。
如果这是代码中常见的模式,并且您认为重复成员名称很容易出错,则可以使用boost::tuple
和boost::fusion
:
#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>(); }
};
您可以消除地址向量并迭代成员(不过我在这里保留了该向量)
#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<I>(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<I>(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<I>(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;
}
您可以使用union:
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;
};
相关文章:
- 在变量名后声明带有 () 的非内部类型与不使用变量名的行为不同。即 std::map<int,char>x(); - 这是怎么回事?
- 在循环中使用相同的变量名可以吗
- 为什么类名与"::"一起使用在变量名之前?
- 使用对象标识符作为变量名
- 如何在C++中的两个不同对象中使用相同的变量名
- 程序使用TCHAR类型和TEXT宏将L附加到变量名
- 如何使用宏来收集变量名
- 为什么我不能使用与类名相同的变量名?
- C++ - 在内部,在定义类的成员函数时,应该使用成员变量名还是其getter函数?
- 如何在C++中使用字符串作为变量名
- 使用Visual Studio 2010时,在将调试器附加到程序时看不到托管变量名
- 使用变量名打开文件
- 如何使用这类变量名
- 将变量名与正则表达式c++一起使用
- 如何通过使用变量名访问QTabWidget类的成员选项卡
- 有没有办法编写一个宏来仅使用变量名(即等效于 std::forward(t))的 FWD<T>(t))进行完美转发?
- 使用字符串作为变量名(C++)
- 使用变量名时触发编译错误
- 使用输入字符串作为变量名
- 使用 "near" 作为变量名时编译器错误