考虑一个简单的数据结构:
struct abc
{
int a;
char b;
}
我有一个变量,其中定义了一些值。现在我想将其打印出来。*a = [some value]
b = [some character]*
如何最好地实现这一点,对于任意结构而无需编写一个针对我遇到的每个结构的转储函数?
考虑一个简单的数据结构:
struct abc
{
int a;
char b;
}
我有一个变量,其中定义了一些值。现在我想将其打印出来。*a = [some value]
b = [some character]*
如何最好地实现这一点,对于任意结构而无需编写一个针对我遇到的每个结构的转储函数?
看起来你已经找到了解决方案,但我会稍微扩展一下。
你所称呼的是“反射”,也就是一个对象描述自身的能力。
大多数语言都可以通过元数据实现反射。例如,在 Python 中,对象的函数和属性存储在字典元素中。
C++ 没有本地反射系统,不像 C# 或 Java,这阻止了(例如)这种自动打印/序列化或反序列化。
但是,C++ 有非常强大的元编程支持,它允许我们(通过使用模板)在编译时模拟反射。这通常使用 Boost.Fusion 来完成,它是一个用于从编译时跨越到运行时的库。
就像链接中演示的例子一样,BOOST_FUSION_ADAPT_STRUCT
宏允许您接受标准的 struct
并为其提供必需的接口,以便被视为 Fusion.Sequence。
另一个例子是使用 Fusion.Vector
或 Fusion.Map
存储类的属性,然后将该序列公开给自动打印/序列化/反序列化方法。
但是,这个系统有一个限制:元编程与面向对象编程不太兼容。
struct Base { char a; }; // Adapt
struct Derived: Base { char b; }; // Adapt
void print(Base const& b) { boost::fusion::for_each<Base>(b, Print()); }
只会打印Base
的成员(这里是a
)。在使用多态性时,您需要在某个时候使用virtual
方法 :)
使用C++17(甚至是C++14)和一些疯狂的俄罗斯黑客技巧,可以部分实现。也就是说,您可以按顺序打印类型值,但无法获取字段名称。
相关库是Antony Polukhin的"magic_get"。具体而言,它提供了一个“对于每个字段”迭代机制,它需要一个带有auto
参数类型的模板化lambda。例如:
struct simple {
int a;
char b;
short d;
};
simple x {42, 'a', 3};
std::stringstream ss;
boost::pfr::for_each_field(
x,
[&ss](auto&& val) {
ss << val << ' ';
}
);
这个答案是从一个相关/重复的问题迁移过来的,因为在这里没有人提到它。
在C++中没有这样的东西,真不幸。
只需要这样做
#include<iostream>
using namespace std;
struct abc
{
int a;
char b;
};
void display(abc myStruct){
cout << "struct abc {"<< endl;
cout << abc.a << endl;
cout << abc.b << endl;
cout << "}" << endl;
}
int main(){
abc myStruct
display(myStruct);
}
只有在结构体是用户定义的且您不确定结构体的内部结构时,才需要使用反射。