diff --git a/include/fmt/color.h b/include/fmt/color.h index 464519e58208..ed697a577519 100644 --- a/include/fmt/color.h +++ b/include/fmt/color.h @@ -492,12 +492,10 @@ inline void vprint(std::FILE* f, const text_style& ts, string_view fmt, "Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -template ::value)> -void print(std::FILE* f, const text_style& ts, const S& format_str, - const Args&... args) { - vprint(f, ts, format_str, - fmt::make_format_args>>(args...)); +template +void print(std::FILE* f, const text_style& ts, format_string fmt, + T&&... args) { + vprint(f, ts, fmt, fmt::make_format_args(args...)); } /** @@ -511,19 +509,15 @@ void print(std::FILE* f, const text_style& ts, const S& format_str, "Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -template ::value)> -void print(const text_style& ts, const S& format_str, const Args&... args) { - return print(stdout, ts, format_str, args...); +template +void print(const text_style& ts, format_string fmt, T&&... args) { + return print(stdout, ts, fmt, std::forward(args)...); } -template > -inline auto vformat( - const text_style& ts, const S& format_str, - basic_format_args>> args) - -> std::basic_string { - basic_memory_buffer buf; - detail::vformat_to(buf, ts, detail::to_string_view(format_str), args); +inline auto vformat(const text_style& ts, string_view fmt, format_args args) + -> std::string { + auto buf = memory_buffer(); + detail::vformat_to(buf, ts, fmt, args); return fmt::to_string(buf); } @@ -539,24 +533,21 @@ inline auto vformat( "The answer is {}", 42); \endrst */ -template > -inline auto format(const text_style& ts, const S& format_str, - const Args&... args) -> std::basic_string { - return fmt::vformat(ts, detail::to_string_view(format_str), - fmt::make_format_args>(args...)); +template +inline auto format(const text_style& ts, format_string fmt, T&&... args) + -> std::string { + return fmt::vformat(ts, fmt, fmt::make_format_args(args...)); } /** Formats a string with the given text_style and writes the output to ``out``. */ -template ::value)> -auto vformat_to(OutputIt out, const text_style& ts, - basic_string_view format_str, - basic_format_args>> args) - -> OutputIt { - auto&& buf = detail::get_buffer(out); - detail::vformat_to(buf, ts, format_str, args); +template ::value)> +auto vformat_to(OutputIt out, const text_style& ts, string_view fmt, + format_args args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, ts, fmt, args); return detail::get_iterator(buf, out); } @@ -572,15 +563,11 @@ auto vformat_to(OutputIt out, const text_style& ts, fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); \endrst */ -template < - typename OutputIt, typename S, typename... Args, - bool enable = detail::is_output_iterator>::value && - detail::is_string::value> -inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, - Args&&... args) -> - typename std::enable_if::type { - return vformat_to(out, ts, detail::to_string_view(format_str), - fmt::make_format_args>>(args...)); +template ::value)> +inline auto format_to(OutputIt out, const text_style& ts, + format_string fmt, T&&... args) -> OutputIt { + return vformat_to(out, ts, fmt, fmt::make_format_args(args...)); } template diff --git a/include/fmt/core.h b/include/fmt/core.h index 16cd51710838..30957db0a147 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -570,12 +570,9 @@ template <> struct is_char : std::true_type {}; namespace detail { -// A base class for compile-time strings. -struct compile_string {}; - -template -struct is_compile_string : std::is_base_of {}; - +// Constructs fmt::basic_string_view from types **implicitly** convertible +// to it, deducing Char. Explicitly convertible types such as compile-time +// strings are intentionally excluded. template ::value)> FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view { return s; @@ -583,25 +580,20 @@ FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view { template ::value)> inline auto to_string_view(const S& s) -> basic_string_view { - return s; // std::basic_string[_view] + return s; } template constexpr auto to_string_view(basic_string_view s) -> basic_string_view { return s; } -template ::value)> -constexpr auto to_string_view(const S& s) - -> basic_string_view { - return basic_string_view(s); -} void to_string_view(...); // Specifies whether S is a string type convertible to fmt::basic_string_view. // It should be a constexpr function but MSVC 2017 fails to compile it in // enable_if and MSVC 2015 fails to compile it as an alias template. // ADL is intentionally disabled as to_string_view is not an extension point. -template +template struct is_string : std::is_class()))> {}; @@ -2673,6 +2665,12 @@ template class format_string_checker { } }; +// A base class for compile-time strings. +struct compile_string {}; + +template +using is_compile_string = std::is_base_of; + // Reports a compile-time error if S is not a valid format string. template ::value)> FMT_INLINE void check_format_string(const S&) { @@ -2754,9 +2752,12 @@ template class basic_format_string { basic_string_view str_; public: - template >::value)> + template < + typename S, + FMT_ENABLE_IF( + std::is_convertible>::value || + (detail::is_compile_string::value && + std::is_constructible, const S&>::value))> FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) { static_assert( detail::count< diff --git a/include/fmt/xchar.h b/include/fmt/xchar.h index 04ba67db0810..5b8254b77e57 100644 --- a/include/fmt/xchar.h +++ b/include/fmt/xchar.h @@ -10,6 +10,7 @@ #include +#include "color.h" #include "format.h" #include "ranges.h" @@ -29,6 +30,17 @@ enum char8_type : unsigned char {}; template using is_exotic_char = bool_constant::value>; +template +struct format_string_char : char_t_impl {}; + +template +struct format_string_char::value>> { + using type = typename S::char_type; +}; + +template +using format_string_char_t = typename format_string_char::type; + inline auto write_loc(back_insert_iterator> out, loc_value value, const format_specs& specs, locale_ref loc) -> bool { @@ -125,7 +137,8 @@ auto format(wformat_string fmt, T&&... args) -> std::wstring { // Pass char_t as a default template parameter instead of using // std::basic_string> to reduce the symbol size. -template , +template , FMT_ENABLE_IF(!std::is_same::value && !std::is_same::value)> auto format(const S& format_str, T&&... args) -> std::basic_string { @@ -133,7 +146,8 @@ auto format(const S& format_str, T&&... args) -> std::basic_string { fmt::make_format_args>(args...)); } -template , +template , FMT_ENABLE_IF(detail::is_locale::value&& detail::is_exotic_char::value)> inline auto vformat( @@ -143,7 +157,8 @@ inline auto vformat( return detail::vformat(loc, detail::to_string_view(format_str), args); } -template , +template , FMT_ENABLE_IF(detail::is_locale::value&& detail::is_exotic_char::value)> inline auto format(const Locale& loc, const S& format_str, T&&... args) @@ -152,7 +167,8 @@ inline auto format(const Locale& loc, const S& format_str, T&&... args) fmt::make_format_args>(args...)); } -template , +template , FMT_ENABLE_IF(detail::is_output_iterator::value&& detail::is_exotic_char::value)> auto vformat_to(OutputIt out, const S& format_str, @@ -164,7 +180,7 @@ auto vformat_to(OutputIt out, const S& format_str, } template , + typename Char = detail::format_string_char_t, FMT_ENABLE_IF(detail::is_output_iterator::value&& detail::is_exotic_char::value)> inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { @@ -173,7 +189,7 @@ inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { } template , + typename Char = detail::format_string_char_t, FMT_ENABLE_IF(detail::is_output_iterator::value&& detail::is_locale::value&& detail::is_exotic_char::value)> @@ -187,7 +203,7 @@ inline auto vformat_to( } template , + typename Char = detail::format_string_char_t, bool enable = detail::is_output_iterator::value && detail::is_locale::value && detail::is_exotic_char::value> @@ -212,16 +228,17 @@ inline auto vformat_to_n( } template , + typename Char = detail::format_string_char_t, FMT_ENABLE_IF(detail::is_output_iterator::value&& detail::is_exotic_char::value)> inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) -> format_to_n_result { - return vformat_to_n(out, n, detail::to_string_view(fmt), + return vformat_to_n(out, n, fmt::basic_string_view(fmt), fmt::make_format_args>(args...)); } -template , +template , FMT_ENABLE_IF(detail::is_exotic_char::value)> inline auto formatted_size(const S& fmt, T&&... args) -> size_t { auto buf = detail::counting_buffer(); @@ -260,6 +277,30 @@ template void println(wformat_string fmt, T&&... args) { return print(L"{}\n", fmt::format(fmt, std::forward(args)...)); } +inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args) + -> std::wstring { + auto buf = wmemory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + return fmt::to_string(buf); +} + +template +inline auto format(const text_style& ts, wformat_string fmt, T&&... args) + -> std::wstring { + return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...)); +} + +template +void print(std::FILE* f, const text_style& ts, wformat_string fmt, + const T&... args) { + vprint(f, ts, fmt, fmt::make_wformat_args(args...)); +} + +template +void print(const text_style& ts, wformat_string fmt, const T&... args) { + return print(stdout, ts, fmt, args...); +} + /** Converts *value* to ``std::wstring`` using the default format for type *T*. */