我想简化以下
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 } {}
};
对于上下文,这是为了实现某种属性内省系统。
答案 0 :(得分:6)
您可以使用Boost Preprocessor。
#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)
我通常会避免“不要这样做,你真的想做那个而不是”答案。但在这种情况下,问题太明显了。
您正在堆上分配内存以获取编译时可用的信息。那太可怕了。
您的实现会不必要地中断默认副本并移动构造函数行为。我希望你知道这一点。我希望每个人重用代码都知道这一点。
我想你想要实现的是访问所有成员的通用方法。做类似以下的事情:
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>(); }
};
答案 2 :(得分: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;
}
答案 3 :(得分:0)
您可以使用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;
};