在 C++ 结构体中打印所有字段的值

23

考虑一个简单的数据结构:

struct abc  
{  
    int a;  
    char b;  
}  
我有一个变量,其中定义了一些值。现在我想将其打印出来。
*a = [some value]  
b = [some character]*

如何最好地实现这一点,对于任意结构而无需编写一个针对我遇到的每个结构的转储函数?


1
写完这个问题后,我随机地在谷歌上搜索,发现了下面的讨论: https://dev59.com/EHI-5IYBdhLWcg3wZ3YR我认为这回答了我所有的疑问。虽然如此,还是感谢大家的回答。 - Zhinkaas
6个回答

30

看起来你已经找到了解决方案,但我会稍微扩展一下。

你所称呼的是“反射”,也就是一个对象描述自身的能力。

大多数语言都可以通过元数据实现反射。例如,在 Python 中,对象的函数和属性存储在字典元素中。

C++ 没有本地反射系统,不像 C# 或 Java,这阻止了(例如)这种自动打印/序列化或反序列化。

但是,C++ 有非常强大的元编程支持,它允许我们(通过使用模板)在编译时模拟反射。这通常使用 Boost.Fusion 来完成,它是一个用于从编译时跨越到运行时的库。

就像链接中演示的例子一样,BOOST_FUSION_ADAPT_STRUCT 宏允许您接受标准的 struct 并为其提供必需的接口,以便被视为 Fusion.Sequence。

另一个例子是使用 Fusion.VectorFusion.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方法 :)


我喜欢fusion.adapt.struct解决方案。特别询问如何进入嵌套的结构字段并使其全部工作 - minghua

3
你需要“反射”来完成这个任务。C++本身并没有提供反射功能,或仅提供了最少限度的信息(类型id/名称)。
有一些库(如CAMP)实现了反射功能,所以如果你真的需要反射,应该使用其中一个库。

2

使用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 << ' ';
    }
);

这个答案是从一个相关/重复的问题迁移过来的,因为在这里没有人提到它。


0

在C++中没有这样的东西,真不幸。


有多种方法可以实现这个:使用模板元编程、解析或使用外部工具生成类。不要忘记,尽管可能不容易或不是您认为的方式,但计算机可以实现许多事情。 - Matthieu M.
现在有一些反射库(https://github.com/rttrorg/rttr),并且反射技术也正在被标准所采纳。这个答案已经过时了。 - Zoe stands with Ukraine

0

如果你在.NET中使用C++,你可以潜在地使用System.Reflection来查看你的结构体内部。然而,非托管的C++很少存储关于对象的那种元数据。


0

只需要这样做

#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);
}

只有在结构体是用户定义的且您不确定结构体的内部结构时,才需要使用反射。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接