fmt 与 Howard Hinnant 的约会:为什么“{}”来自 fmt::to_string? fmt 和日期的最佳实践?
fmt with Howard Hinnant's date: why "{}" from fmt::to_string? Best practice for fmt and date?
TL;DR:我正在为 fmt and Howard Hinnant's date library. With date::year_month_day d{};
, why does fmt::to_string(d)
return "{}"
while fmt::format("{}", d)
works fine, returning "0000-00-00"
? Example on godbolt.
实现自定义格式化程序
我正在使用 date library and trying to switch from iostreams to fmt。我需要以 YYYY-MM-DD 格式格式化 date::year_month_day
,所以我编写了一个自定义格式化程序(date::year_month_day
的 fmt::formatter 的模板专业化):
template<>
struct fmt::formatter<date::year_month_day> {
template<typename ParseContext>
auto parse(ParseContext & ctx) { return ctx.begin(); }
template<typename FormatContext>
auto format(const date::year_month_day & ymd, FormatContext & ctx) -> decltype(ctx.out()) {
const int year = (int)ymd.year();
const unsigned month = (unsigned)ymd.month();
const unsigned day = (unsigned)ymd.day();
return fmt::format_to(ctx.out(), "{:04}-{:02}-{:02}", year, month, day);
}
};
完整的最小工作示例,有两个工作示例和一个失败示例,是 available on godbolt。
使用该自定义格式化程序,fmt::format("{}", date::year_month_day{})
按预期工作,returning "0000-00-00"
。 fmt::to_string(date::year_month_day{})
应该是 return 相同的结果,但是 return 是 "{}"
。
将 date::year_month_day
和来自 date
的其他类型格式化为 fmt
(包括 fmt::to_string()
)的最佳方式是什么?为什么我得到那个 "{}"
?
我还不能使用支持 C++20 日期的编译器:据我所知,截至 2020 年 6 月,C++20 std::chrono 的日历和时区部分还没有完整的实现.
更新:对自定义空结构使用自定义格式化程序效果很好,format("{}", s)
和 to_string(s)
的结果相同,请参见上面的 godbolt link 示例。所以 date::year_month_day
一定有什么特别之处打破了 fmt::to_string()
.
这是依赖于参数的查找的不幸结果:fmt::to_string
调用 format
,最终被解析为 date::format
而不是 fmt::format
。解决方法是在 fmt::to_string
中完全限定对 format
的调用,因为它取决于用户定义的类型。
更新:此问题已在 https://github.com/fmtlib/fmt/commit/2cac8a9d2e36cd920a9a60ec5b776c187e843fbb 中修复。
TL;DR:我正在为 fmt and Howard Hinnant's date library. With date::year_month_day d{};
, why does fmt::to_string(d)
return "{}"
while fmt::format("{}", d)
works fine, returning "0000-00-00"
? Example on godbolt.
我正在使用 date library and trying to switch from iostreams to fmt。我需要以 YYYY-MM-DD 格式格式化 date::year_month_day
,所以我编写了一个自定义格式化程序(date::year_month_day
的 fmt::formatter 的模板专业化):
template<>
struct fmt::formatter<date::year_month_day> {
template<typename ParseContext>
auto parse(ParseContext & ctx) { return ctx.begin(); }
template<typename FormatContext>
auto format(const date::year_month_day & ymd, FormatContext & ctx) -> decltype(ctx.out()) {
const int year = (int)ymd.year();
const unsigned month = (unsigned)ymd.month();
const unsigned day = (unsigned)ymd.day();
return fmt::format_to(ctx.out(), "{:04}-{:02}-{:02}", year, month, day);
}
};
完整的最小工作示例,有两个工作示例和一个失败示例,是 available on godbolt。
使用该自定义格式化程序,fmt::format("{}", date::year_month_day{})
按预期工作,returning "0000-00-00"
。 fmt::to_string(date::year_month_day{})
应该是 return 相同的结果,但是 return 是 "{}"
。
将 date::year_month_day
和来自 date
的其他类型格式化为 fmt
(包括 fmt::to_string()
)的最佳方式是什么?为什么我得到那个 "{}"
?
我还不能使用支持 C++20 日期的编译器:据我所知,截至 2020 年 6 月,C++20 std::chrono 的日历和时区部分还没有完整的实现.
更新:对自定义空结构使用自定义格式化程序效果很好,format("{}", s)
和 to_string(s)
的结果相同,请参见上面的 godbolt link 示例。所以 date::year_month_day
一定有什么特别之处打破了 fmt::to_string()
.
这是依赖于参数的查找的不幸结果:fmt::to_string
调用 format
,最终被解析为 date::format
而不是 fmt::format
。解决方法是在 fmt::to_string
中完全限定对 format
的调用,因为它取决于用户定义的类型。
更新:此问题已在 https://github.com/fmtlib/fmt/commit/2cac8a9d2e36cd920a9a60ec5b776c187e843fbb 中修复。