在我当前的项目中,我需要一个自定义的非常简单的“序列化”表示几个琐碎的数据传输对象 (DTO) 结构。在第一次想出一个定制的解决方案之后,那是一个大的 PITA,我有使用 {fmt} 的想法。
所以最近几天我正在通过fmt::formatter
模板专业化机制的扩展来处理自定义类型的格式。因此,此博客和您的文档非常有帮助。
经过一番折腾,我想出了一个非常通用的 poc 解决方案,它允许以多种自定义格式格式化结构,看起来有点像下面这样:
struct Inner {
double x;
std::string y;
int z;
};
struct Outer {
int a;
std::string b;
Inner inner;
};
template<>
struct reflection<Outer> {
/*definition of class name and field names has to be provided manually...*/
};
template<>
struct reflection<Inner> {
/*definition of class name and field names has to provided manually...*/
};
/*
...
couple dozend lines of meta programming and fmt::formatter specializations.
...
*/
auto outer = Outer{.a=1,.b="hello",.inner={.x=3.12,.y=" ",.z=2}};
std::string simple = fmt::format("{:s}", outer); // :s means format as simple
assert(simple == "a|hello|3.12| |2");
assert(fmt::format("{:s;}", outer) == "a;hello;3.12; ;2");
std::string extended = fmt::format("{:e}",outer); // :e means format as extended
assert(extended == "Outer{.a=1, .b=hello, .inner=Inner{.x=3.12, .y= , .z=2}}");
显然,没有标准的方法来反映结构的字段和名称,因此必须手动提供反射结构,或者例如通过宏魔术。但这是一个不同的话题,我不想在这里讨论。- 如果我们幸运的话,我们会在 c++23 \o/ 中得到一些最小的编译时间反射。让我们希望!
我把所有这些放在了这个 repo中。
实际问题:
通过 {fmt} 提供的简单反射 API 格式化用户定义的类型是您认为未来可能对 {fmt} 进行扩展的东西吗?我想象一个场景,其中预定义了几个简单的格式化模式,用户只需要为他的类型提供反射。
有了这个,我什至可以看到像fmt::format("{:json,prety,tabwith=4}", outer)
在地平线上的格式化表达式。
另外,也许我只是在重新发明轮子,所以如果有类似的东西,基于 {fmt} 那里 - 告诉我!:)
无论如何,感谢您为社区提供了很棒的工具,并祝贺您将其变成了 c++20!
问候,马丁