在C ++中是否可以遍历Struct或Class来查找其所有成员?例如,如果我有结构a和类b:
struct a
{
int a;
int b;
int c;
}
class b
{
public:
int a;
int b;
private:
int c;
}
是否可以循环它们以获得一个打印语句说“struct a has int named a,b,c”或“Class b has int named a,b,c”
答案 0 :(得分:27)
有两种方法可以做到这一点,但您需要使用一些宏来定义或修改结构。
您可以使用this answer中给出的REFLECTABLE
宏来定义这样的结构:
struct A
{
REFLECTABLE
(
(int) a,
(int) b,
(int) c
)
};
然后你可以迭代字段并打印每个值,如下所示:
struct print_visitor
{
template<class FieldData>
void operator()(FieldData f)
{
std::cout << f.name() << "=" << f.get() << std::endl;
}
};
template<class T>
void print_fields(T & x)
{
visit_each(x, print_visitor());
}
A x;
print_fields(x);
另一种方法是将结构调整为融合序列(参见the documentation)。这是一个例子:
struct A
{
int a;
int b;
int c;
};
BOOST_FUSION_ADAPT_STRUCT
(
A,
(int, a)
(int, b)
(int, c)
)
然后您也可以使用以下方式打印字段:
struct print_visitor
{
template<class Index, class C>
void operator()(Index, C & c)
{
std::cout << boost::fusion::extension::struct_member_name<C, Index::value>::call()
<< "="
<< boost:::fusion::at<Index>(c)
<< std::endl;
}
};
template<class C>
void print_fields(C & c)
{
typedef boost::mpl::range_c<int,0, boost::fusion::result_of::size<C>::type::value> range;
boost::mpl::for_each<range>(boost::bind<void>(print_visitor(), boost::ref(c), _1));
}
答案 1 :(得分:14)
不,这是不可能的,因为C ++中没有反映。
答案 2 :(得分:2)
如果您拥有相同类型的成员(就像您在第一个特定示例中所做的那样),您希望(a)具有名称,并且(b)可迭代,那么您可以将数组与枚举组合:< / p>
enum names { alice, bob, carl };
struct myStruct;
{
std::array<int, 3> members;
}
然后你们两个都可以
myStruct instance;
// iterate through them...
for (auto elem : instance.members)
{
// work with each element in sequence
}
// and call them by name, taking away the need to remember which element is the first, etc.
instance[bob] = 100;
显然不是一般解决方案,但我发现这在我自己的工作中很有用。
答案 3 :(得分:0)
假设您的成员变量具有相同的类型,则可以执行从GLM库中窃取的类似操作:
class Point
{
Point();// you must re-implement the default constructor if you need one
union
{
struct
{
double x;
double y;
double z;
}
std::array<double, 3> components;
}
}
从可维护性的角度来看,这不是最优雅的解决方案,手动计算要解决问题的变量数量。但是,它将在没有其他库或宏的情况下工作,并且适用于您希望这种行为的大多数情况。
联合不支持自动生成的默认构造函数,因此您需要编写一个告诉对象如何初始化联合的模型。
for (double component : point.components)
{
// do something
}
答案 4 :(得分:0)
假定所有类成员都属于同一类型,则可以使用称为结构化绑定的C ++ 17功能。假设所有成员都是公开的,那么它将起作用:
struct SI
{
int x;
int y;
int z;
};
struct SD
{
double x;
double y;
double z;
};
template<typename T>
void print(const T &val)
{
const auto& [a, b, c] = val;
for (auto elem : {a, b, c})
{
std::cout << elem << " ";
}
std::cout << std::endl;
}
这将与具有完全相同(可复制)类型的3个公共元素的任何结构一起使用。如果是非公开成员,则该功能必须是朋友或成员。但是,这种方法不能轻易扩展到任意数量的元素。
答案 5 :(得分:0)
这是 QCTDevs 答案的改进版本:
class MyClass
{
union
{
struct Memberstruct
{
double test0;
double test1;
double test2;
} m;
array<double, sizeof( Memberstruct ) / sizeof( double )> memberarray;
};
bool test() { &(m.test1) == &(memberarray[1]); }
};
要求仍然是具有所有相同的数据类型,如果需要,您还需要实现默认的构造函数。
改进之处在于您无需手动维护数组的大小。
与没有此解决方法的类相比,缺点是语法有所改变。