Move generic format functions to format.h

This commit is contained in:
Victor Zverovich 2021-05-18 07:25:05 -07:00
parent 9a92eb4158
commit 21d93bfd33
5 changed files with 187 additions and 154 deletions

View File

@ -157,7 +157,8 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
\endrst \endrst
*/ */
#ifdef __cpp_if_constexpr #ifdef __cpp_if_constexpr
# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string) # define FMT_COMPILE(s) \
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
#else #else
# define FMT_COMPILE(s) FMT_STRING(s) # define FMT_COMPILE(s) FMT_STRING(s)
#endif #endif
@ -428,7 +429,7 @@ template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
typename S> typename S>
constexpr auto parse_replacement_field_then_tail(S format_str) { constexpr auto parse_replacement_field_then_tail(S format_str) {
using char_type = typename S::char_type; using char_type = typename S::char_type;
constexpr basic_string_view<char_type> str = format_str; constexpr auto str = basic_string_view<char_type>(format_str);
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
if constexpr (c == '}') { if constexpr (c == '}') {
return parse_tail<Args, END_POS + 1, NEXT_ID>( return parse_tail<Args, END_POS + 1, NEXT_ID>(
@ -449,7 +450,7 @@ constexpr auto parse_replacement_field_then_tail(S format_str) {
template <typename Args, size_t POS, int ID, typename S> template <typename Args, size_t POS, int ID, typename S>
constexpr auto compile_format_string(S format_str) { constexpr auto compile_format_string(S format_str) {
using char_type = typename S::char_type; using char_type = typename S::char_type;
constexpr basic_string_view<char_type> str = format_str; constexpr auto str = basic_string_view<char_type>(format_str);
if constexpr (str[POS] == '{') { if constexpr (str[POS] == '{') {
if constexpr (POS + 1 == str.size()) if constexpr (POS + 1 == str.size())
throw format_error("unmatched '{' in format string"); throw format_error("unmatched '{' in format string");
@ -518,7 +519,7 @@ constexpr auto compile_format_string(S format_str) {
template <typename... Args, typename S, template <typename... Args, typename S,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
constexpr auto compile(S format_str) { constexpr auto compile(S format_str) {
constexpr basic_string_view<typename S::char_type> str = format_str; constexpr auto str = basic_string_view<typename S::char_type>(format_str);
if constexpr (str.size() == 0) { if constexpr (str.size() == 0) {
return detail::make_text(str, 0, 0); return detail::make_text(str, 0, 0);
} else { } else {
@ -557,7 +558,7 @@ template <typename S, typename... Args,
FMT_INLINE std::basic_string<typename S::char_type> format(const S&, FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) { Args&&... args) {
if constexpr (std::is_same<typename S::char_type, char>::value) { if constexpr (std::is_same<typename S::char_type, char>::value) {
constexpr basic_string_view<typename S::char_type> str = S(); constexpr auto str = basic_string_view<typename S::char_type>(S());
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
const auto& first = detail::first(args...); const auto& first = detail::first(args...);
if constexpr (detail::is_named_arg< if constexpr (detail::is_named_arg<

View File

@ -550,7 +550,7 @@ struct is_compile_string : std::is_base_of<compile_string, S> {};
template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)> template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) { constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) {
return s; return basic_string_view<typename S::char_type>(s);
} }
FMT_BEGIN_DETAIL_NAMESPACE FMT_BEGIN_DETAIL_NAMESPACE
@ -841,6 +841,8 @@ class iterator_buffer final : public Traits, public buffer<T> {
public: public:
explicit iterator_buffer(OutputIt out, size_t n = buffer_size) explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
: Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) {} : Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) {}
iterator_buffer(iterator_buffer&& other)
: Traits(other), buffer<T>(data_, 0, buffer_size), out_(other.out_) {}
~iterator_buffer() { flush(); } ~iterator_buffer() { flush(); }
OutputIt out() { OutputIt out() {
@ -901,6 +903,7 @@ template <typename T = char> class counting_buffer final : public buffer<T> {
public: public:
counting_buffer() : buffer<T>(data_, 0, buffer_size) {} counting_buffer() : buffer<T>(data_, 0, buffer_size) {}
counting_buffer(counting_buffer&&) : buffer<T>(data_, 0, buffer_size) {}
size_t count() { return count_ + this->size(); } size_t count() { return count_ + this->size(); }
}; };
@ -2679,13 +2682,13 @@ constexpr auto compile_string_to_view(std_string_view<Char> s)
return {s.data(), s.size()}; return {s.data(), s.size()};
} }
#define FMT_STRING_IMPL(s, base) \ #define FMT_STRING_IMPL(s, base, explicit) \
[] { \ [] { \
/* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \
/* Use a macro-like name to avoid shadowing warnings. */ \ /* Use a macro-like name to avoid shadowing warnings. */ \
struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \
using char_type = fmt::remove_cvref_t<decltype(s[0])>; \ using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
FMT_MAYBE_UNUSED FMT_CONSTEXPR \ FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \
operator fmt::basic_string_view<char_type>() const { \ operator fmt::basic_string_view<char_type>() const { \
return fmt::detail::compile_string_to_view<char_type>(s); \ return fmt::detail::compile_string_to_view<char_type>(s); \
} \ } \
@ -2703,18 +2706,11 @@ constexpr auto compile_string_to_view(std_string_view<Char> s)
std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); std::string s = fmt::format(FMT_STRING("{:d}"), "foo");
\endrst \endrst
*/ */
#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string) #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, )
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto vformat(basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char>;
FMT_API auto vformat(string_view format_str, format_args args) -> std::string;
template <typename Char> template <typename Char>
void vformat_to( void vformat_to(
buffer<Char>& buf, basic_string_view<Char> format_str, buffer<type_identity_t<Char>>& buf, basic_string_view<Char> format_str,
basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args, basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
detail::locale_ref loc = {}); detail::locale_ref loc = {});
@ -2806,99 +2802,14 @@ struct formatter<T, Char,
-> decltype(ctx.out()); -> decltype(ctx.out());
}; };
/** Formats a string and writes the output to ``out``. */
template <typename OutputIt, typename S, typename Char = char_t<S>,
bool enable = detail::is_output_iterator<OutputIt, Char>::value>
auto vformat_to(OutputIt out, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> enable_if_t<enable, OutputIt> {
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
detail::vformat_to(buf, to_string_view(format_str), args);
return detail::get_iterator(buf);
}
/**
\rst
Formats arguments, writes the result to the output iterator ``out`` and returns
the iterator past the end of the output range.
**Example**::
std::vector<char> out;
fmt::format_to(std::back_inserter(out), "{}", 42);
\endrst
*/
// We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3.
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char_t<S>>::value)>
inline auto format_to(OutputIt out, const S& format_str, Args&&... args)
-> OutputIt {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return vformat_to(out, to_string_view(format_str), vargs);
}
template <typename OutputIt> struct format_to_n_result {
/** Iterator past the end of the output range. */
OutputIt out;
/** Total (not truncated) output size. */
size_t size;
};
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
inline auto vformat_to_n(
OutputIt out, size_t n, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> format_to_n_result<OutputIt> {
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
n);
detail::vformat_to(buf, format_str, args);
return {buf.out(), buf.count()};
}
/**
\rst
Formats arguments, writes up to ``n`` characters of the result to the output
iterator ``out`` and returns the total output size and the iterator past the
end of the output range.
\endrst
*/
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char_t<S>>::value)>
inline auto format_to_n(OutputIt out, size_t n, const S& format_str,
const Args&... args) -> format_to_n_result<OutputIt> {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return vformat_to_n(out, n, to_string_view(format_str), vargs);
}
/**
Returns the number of characters in the output of
``format(format_str, args...)``.
*/
template <typename S, typename... Args, typename Char = char_t<S>>
inline auto formatted_size(const S& format_str, Args&&... args) -> size_t {
detail::counting_buffer<> buf;
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
detail::vformat_to(buf, to_string_view(format_str), vargs);
return buf.count();
}
template <typename S, typename Char = char_t<S>>
FMT_INLINE auto vformat(
const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
return detail::vformat(to_string_view(format_str), args);
}
template <typename Char, typename... Args> class basic_format_string { template <typename Char, typename... Args> class basic_format_string {
private: private:
basic_string_view<Char> str; basic_string_view<Char> str_;
public: public:
#if FMT_COMPILE_TIME_CHECKS #if FMT_COMPILE_TIME_CHECKS
template <size_t N> template <size_t N>
consteval basic_format_string(const char (&s)[N]) : str(s) { consteval basic_format_string(const char (&s)[N]) : str_(s) {
if constexpr (detail::count_named_args<Args...>() == 0) { if constexpr (detail::count_named_args<Args...>() == 0) {
using checker = detail::format_string_checker<char, detail::error_handler, using checker = detail::format_string_checker<char, detail::error_handler,
remove_cvref_t<Args>...>; remove_cvref_t<Args>...>;
@ -2907,10 +2818,10 @@ template <typename Char, typename... Args> class basic_format_string {
} }
#endif #endif
template <typename T, template <typename S,
FMT_ENABLE_IF(std::is_constructible<basic_string_view<Char>, FMT_ENABLE_IF(
const T&>::value)> std::is_convertible<const S&, basic_string_view<Char>>::value)>
basic_format_string(const T& s) : str(s) { basic_format_string(const S& s) : str_(s) {
static_assert( static_assert(
detail::count< detail::count<
(std::is_base_of<detail::view, remove_reference_t<Args>>::value && (std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
@ -2919,7 +2830,7 @@ template <typename Char, typename... Args> class basic_format_string {
detail::check_format_string<Args...>(s); detail::check_format_string<Args...>(s);
} }
FMT_INLINE operator basic_string_view<Char>() const { return str; } FMT_INLINE operator basic_string_view<Char>() const { return str_; }
}; };
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
@ -2930,9 +2841,12 @@ template <typename... Args>
using format_string = basic_format_string<char, type_identity_t<Args>...>; using format_string = basic_format_string<char, type_identity_t<Args>...>;
#endif #endif
FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
/** /**
\rst \rst
Formats arguments and returns the result as a string. Formats ``args`` according to specifications in ``fmt`` and returns the result
as a string.
**Example**:: **Example**::
@ -2941,34 +2855,84 @@ using format_string = basic_format_string<char, type_identity_t<Args>...>;
\endrst \endrst
*/ */
template <typename... T> template <typename... T>
FMT_INLINE auto format(format_string<T...> str, T&&... args) -> std::string { FMT_INLINE auto format(format_string<T...> fmt, T&&... args) -> std::string {
return detail::vformat(str, make_format_args(args...)); return vformat(fmt, make_format_args(args...));
} }
FMT_API void vprint(std::FILE*, string_view, format_args); /** Formats a string and writes the output to ``out``. */
FMT_API void vprint(string_view, format_args); template <typename OutputIt,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt {
decltype(detail::get_buffer<char>(out)) buf(detail::get_buffer_init(out));
detail::vformat_to(buf, string_view(fmt), args);
return detail::get_iterator(buf);
}
/**
\rst
Formats ``args`` according to specifications in ``fmt``, writes the result to
the output iterator ``out`` and returns the iterator past the end of the output
range.
**Example**::
auto out = std::vector<char>();
fmt::format_to(std::back_inserter(out), "{}", 42);
\endrst
*/
template <typename OutputIt, typename... T,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
inline auto format_to(OutputIt out, format_string<T...> fmt, T&&... args)
-> OutputIt {
return vformat_to(out, fmt, make_format_args(args...));
}
template <typename OutputIt> struct format_to_n_result {
/** Iterator past the end of the output range. */
OutputIt out;
/** Total (not truncated) output size. */
size_t size;
};
template <typename OutputIt, typename... T,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args)
-> format_to_n_result<OutputIt> {
using buffer =
detail::iterator_buffer<OutputIt, char, detail::fixed_buffer_traits>;
auto buf = buffer(out, n);
detail::vformat_to(buf, fmt, args);
return {buf.out(), buf.count()};
}
/** /**
\rst \rst
Formats ``args`` according to specifications in ``str`` and writes the Formats ``args`` according to specifications in ``fmt``, writes up to ``n``
output to the file ``f``. Strings are assumed to be in UTF-8 unless the characters of the result to the output iterator ``out`` and returns the total
``FMT_UNICODE`` macro is set to 0. (not truncated) output size and the iterator past the end of the output range.
**Example**::
fmt::print(stderr, "Don't {}!", "panic");
\endrst \endrst
*/ */
template <typename... T> template <typename OutputIt, typename... T,
inline void print(std::FILE* f, format_string<T...> str, T&&... args) { FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
const auto& vargs = make_format_args(args...); inline auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt,
return detail::is_utf8() ? vprint(f, str, vargs) const T&... args) -> format_to_n_result<OutputIt> {
: detail::vprint_mojibake(f, str, vargs); return vformat_to_n(out, n, fmt, make_format_args(args...));
} }
/** Returns the number of chars in the output of ``format(fmt, args...)``. */
template <typename... T>
inline auto formatted_size(format_string<T...> fmt, T&&... args) -> size_t {
auto buf = detail::counting_buffer<>();
detail::vformat_to(buf, string_view(fmt), make_format_args(args...));
return buf.count();
}
FMT_API void vprint(string_view, format_args);
FMT_API void vprint(std::FILE*, string_view, format_args);
/** /**
\rst \rst
Formats ``args`` according to specifications in ``str`` and writes the output Formats ``args`` according to specifications in ``fmt`` and writes the output
to ``stdout``. Strings are assumed to be in UTF-8 unless the ``FMT_UNICODE`` to ``stdout``. Strings are assumed to be in UTF-8 unless the ``FMT_UNICODE``
macro is set to 0. macro is set to 0.
@ -2978,10 +2942,28 @@ inline void print(std::FILE* f, format_string<T...> str, T&&... args) {
\endrst \endrst
*/ */
template <typename... T> template <typename... T>
inline void print(format_string<T...> str, T&&... args) { inline void print(format_string<T...> fmt, T&&... args) {
const auto& vargs = make_format_args(args...); const auto& vargs = make_format_args(args...);
return detail::is_utf8() ? vprint(str, vargs) return detail::is_utf8() ? vprint(fmt, vargs)
: detail::vprint_mojibake(stdout, str, vargs); : detail::vprint_mojibake(stdout, fmt, vargs);
}
/**
\rst
Formats ``args`` according to specifications in ``fmt`` and writes the
output to the file ``f``. Strings are assumed to be in UTF-8 unless the
``FMT_UNICODE`` macro is set to 0.
**Example**::
fmt::print(stderr, "Don't {}!", "panic");
\endrst
*/
template <typename... T>
inline void print(std::FILE* f, format_string<T...> fmt, T&&... args) {
const auto& vargs = make_format_args(args...);
return detail::is_utf8() ? vprint(f, fmt, vargs)
: detail::vprint_mojibake(f, fmt, vargs);
} }
FMT_MODULE_EXPORT_END FMT_MODULE_EXPORT_END

View File

@ -2575,14 +2575,14 @@ FMT_FUNC void report_system_error(int error_code,
report_error(format_system_error, error_code, message); report_error(format_system_error, error_code, message);
} }
FMT_FUNC std::string detail::vformat(string_view format_str, format_args args) { FMT_FUNC std::string vformat(string_view fmt, format_args args) {
if (format_str.size() == 2 && equal2(format_str.data(), "{}")) { if (fmt.size() == 2 && detail::equal2(fmt.data(), "{}")) {
auto arg = args.get(0); auto arg = args.get(0);
if (!arg) error_handler().on_error("argument not found"); if (!arg) detail::error_handler().on_error("argument not found");
return visit_format_arg(stringifier(), arg); return visit_format_arg(detail::stringifier(), arg);
} }
memory_buffer buffer; memory_buffer buffer;
detail::vformat_to(buffer, format_str, args); detail::vformat_to(buffer, fmt, args);
return to_string(buffer); return to_string(buffer);
} }

View File

@ -2573,7 +2573,8 @@ FMT_MODULE_EXPORT_END
template <typename Char> template <typename Char>
void detail::vformat_to( void detail::vformat_to(
detail::buffer<Char>& buf, basic_string_view<Char> format_str, detail::buffer<type_identity_t<Char>>& buf,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args, basic_format_args<buffer_context<type_identity_t<Char>>> args,
detail::locale_ref loc) { detail::locale_ref loc) {
using iterator = typename buffer_context<Char>::iterator; using iterator = typename buffer_context<Char>::iterator;
@ -2621,6 +2622,14 @@ extern template int snprintf_float<long double>(long double value,
FMT_MODULE_EXPORT_BEGIN FMT_MODULE_EXPORT_BEGIN
template <typename OutputIt, typename Char = char>
using format_context_t FMT_DEPRECATED_ALIAS =
basic_format_context<OutputIt, Char>;
template <typename OutputIt, typename Char = char>
using format_args_t FMT_DEPRECATED_ALIAS =
basic_format_args<basic_format_context<OutputIt, Char>>;
template <typename S, typename Char = char_t<S>, template <typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_string<S>::value)> FMT_ENABLE_IF(detail::is_string<S>::value)>
inline void vformat_to( inline void vformat_to(
@ -2639,18 +2648,61 @@ inline auto format_to(basic_memory_buffer<Char, SIZE>& buf, const S& format_str,
return detail::buffer_appender<Char>(buf); return detail::buffer_appender<Char>(buf);
} }
template <typename OutputIt, typename Char = char> template <typename OutputIt, typename S, typename Char = char_t<S>,
using format_context_t FMT_DEPRECATED_ALIAS = FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
basic_format_context<OutputIt, Char>; !std::is_same<Char, char>::value)>
auto vformat_to(OutputIt out, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> OutputIt {
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
detail::vformat_to(buf, to_string_view(format_str), args);
return detail::get_iterator(buf);
}
template <typename OutputIt, typename Char = char> template <typename OutputIt, typename S, typename... Args,
using format_args_t FMT_DEPRECATED_ALIAS = typename Char = char_t<S>,
basic_format_args<basic_format_context<OutputIt, Char>>; FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
!std::is_same<Char, char>::value)>
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
return vformat_to(out, to_string_view(fmt), vargs);
}
template <typename Char, enable_if_t<(!std::is_same<Char, char>::value), int>> template <typename OutputIt, typename Char, typename... Args,
auto detail::vformat( FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
basic_string_view<Char> format_str, !std::is_same<Char, char>::value)>
inline auto vformat_to_n(
OutputIt out, size_t n, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> format_to_n_result<OutputIt> {
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
n);
detail::vformat_to(buf, format_str, args);
return {buf.out(), buf.count()};
}
template <typename OutputIt, typename S, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
!std::is_same<Char, char>::value)>
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
const Args&... args) -> format_to_n_result<OutputIt> {
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
return vformat_to_n(out, n, to_string_view(fmt), vargs);
}
template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
detail::counting_buffer<> buf;
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
detail::vformat_to(buf, to_string_view(fmt), vargs);
return buf.count();
}
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto vformat(basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> { -> std::basic_string<Char> {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
detail::vformat_to(buffer, format_str, args); detail::vformat_to(buffer, format_str, args);
@ -2661,10 +2713,9 @@ auto detail::vformat(
// std::basic_string<char_t<S>> to reduce the symbol size. // std::basic_string<char_t<S>> to reduce the symbol size.
template <typename S, typename... Args, typename Char = char_t<S>, template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value)> FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
FMT_INLINE auto format(const S& format_str, Args&&... args) auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
-> std::basic_string<Char> {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return detail::vformat(to_string_view(format_str), vargs); return vformat(to_string_view(format_str), vargs);
} }
FMT_MODULE_EXPORT_END FMT_MODULE_EXPORT_END

View File

@ -432,13 +432,12 @@ class ostream final : private detail::buffer<char> {
} }
/** /**
Formats ``args`` according to specifications in ``format_str`` and writes Formats ``args`` according to specifications in ``fmt`` and writes the
the output to the file. output to the file.
*/ */
template <typename S, typename... Args> template <typename... T> void print(format_string<T...> fmt, T&&... args) {
void print(const S& format_str, Args&&... args) { vformat_to(detail::buffer_appender<char>(*this), fmt,
format_to(detail::buffer_appender<char>(*this), format_str, make_format_args(args...));
std::forward<Args>(args)...);
} }
}; };