如何将std::format的格式信息转发给自定义类型的formatter?
在MSVC中为自定义类型实现带格式转发的std::format支持
你的需求中,直接用std::format("{:x}{:*^10}", person)会触发编译错误——因为std::format要求占位符数量必须和传入的参数数量严格匹配,这里2个占位符对应1个Person参数,不符合语法规则。
要实现类似“用单个Person参数对应多个格式占位符”的效果,可以通过以下两种方式解决:
方式一:自定义formatter解析复合格式说明
让std::formatter<Person>支持解析复合格式字符串,通过分隔符(比如分号)区分两个成员的格式规则,用单个占位符完成多成员的格式化:
#include <format> #include <iostream> #include <string> #include <stdexcept> class Person { public: int age; std::string name; }; template <> struct std::formatter<Person> { std::string age_fmt; std::string name_fmt; // 解析格式说明,例如 "{:x;*^10}" 会拆分为age_fmt="x",name_fmt="*^10" constexpr auto parse(std::format_parse_context& ctx) { auto it = ctx.begin(); const auto end = ctx.end(); // 读取age的格式规则,直到遇到分号或格式结束符 while (it != end && *it != ';' && *it != '}') { age_fmt += *it++; } // 如果存在分号,继续读取name的格式规则 if (it != end && *it == ';') { ++it; while (it != end && *it != '}') { name_fmt += *it++; } } // 格式串必须以 } 结尾,否则抛出错误 if (it != end && *it != '}') { throw std::format_error("invalid Person format specifier"); } return it; } template <typename FormatContext> auto format(const Person& p, FormatContext& ctx) { // 根据解析出的格式规则,分别格式化age和name if (age_fmt.empty() && name_fmt.empty()) { return std::format_to(ctx.out(), "{} {}", p.age, p.name); } else if (name_fmt.empty()) { return std::format_to(ctx.out(), "{:" + age_fmt + "} {}", p.age, p.name); } else if (age_fmt.empty()) { return std::format_to(ctx.out(), "{} {:" + name_fmt + "}", p.age, p.name); } else { return std::format_to(ctx.out(), "{:" + age_fmt + "} {:" + name_fmt + "}", p.age, p.name); } } }; int main() { Person person{30, "John Doe"}; // 使用复合格式说明,分号分隔age和name的格式 std::cout << std::format("{:x;*^10}", person) << '\n'; // 输出结果:1e ****John Doe**** return 0; }
方式二:自定义格式化函数
如果想直接复用原格式串"{:x}{:*^10}",可以编写一个封装函数,自动将Person的成员作为参数传入std::format:
#include <format> #include <iostream> #include <string> #include <string_view> class Person { public: int age; std::string name; }; // 自定义格式化函数,自动拆分Person的成员 template <typename... Args> std::string format_person(std::string_view fmt, const Person& p) { return std::format(fmt, p.age, p.name); } int main() { Person person{30, "John Doe"}; // 直接使用原格式串调用自定义函数 std::cout << format_person("{:x}{:*^10}", person) << '\n'; // 输出结果:1e****John Doe**** return 0; }
内容的提问来源于stack exchange,提问作者Ne C
相关产品推荐
相关产品推荐

