diff --git a/doc/api.rst b/doc/api.rst index 4b7f4f8e..c48dfb0c 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -145,6 +145,12 @@ argument type doesn't match its format specification. .. doxygenclass:: fmt::PrintfFormatter :members: +.. doxygenclass:: fmt::BasicPrintfArgFormatter + :members: + +.. doxygenclass:: fmt::PrintfArgFormatter + :members: + Write API ========= diff --git a/fmt/format.h b/fmt/format.h index 1cca4356..44bbf047 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -381,6 +381,9 @@ typedef BasicWriter WWriter; template class ArgFormatter; +template +class BasicPrintfArgFormatter; + template > class BasicFormatter; @@ -1319,9 +1322,6 @@ class RuntimeError : public std::runtime_error { ~RuntimeError() throw(); }; -template -class BasicPrintfArgFormatter; - template class ArgMap; } // namespace internal @@ -1979,7 +1979,7 @@ class BasicArgFormatter : public internal::ArgFormatterBase { : internal::ArgFormatterBase(formatter.writer(), spec), formatter_(formatter), format_(fmt) {} - /** Formats argument of a custom (user-defined) type. */ + /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { c.format(&formatter_, c.value, &format_); } @@ -2406,7 +2406,7 @@ class BasicWriter { friend class internal::ArgFormatterBase; template - friend class internal::BasicPrintfArgFormatter; + friend class BasicPrintfArgFormatter; protected: /** diff --git a/fmt/printf.h b/fmt/printf.h index 78cda420..080b0023 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -170,21 +170,47 @@ class WidthHandler : public ArgVisitor { return static_cast(width); } }; +} // namespace internal +/** + \rst + A ``printf`` argument formatter based on the `curiously recurring template + pattern `_. + + To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some + or all of the visit methods with the same signatures as the methods in + `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. + Pass the subclass as the *Impl* template parameter. When a formatting + function processes an argument, it will dispatch to a visit method + specific to the argument type. For example, if the argument type is + ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass + will be called. If the subclass doesn't contain a method with this signature, + then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its + superclass will be called. + \endrst + */ template -class BasicPrintfArgFormatter : public ArgFormatterBase { +class BasicPrintfArgFormatter : public internal::ArgFormatterBase { private: void write_null_pointer() { this->spec().type_ = 0; this->write("(nil)"); } - typedef ArgFormatterBase Base; + typedef internal::ArgFormatterBase Base; public: - BasicPrintfArgFormatter(BasicWriter &w, FormatSpec &s) - : ArgFormatterBase(w, s) {} + /** + \rst + Constructs an argument formatter object. + *writer* is a reference to the output writer and *spec* contains format + specifier information for standard argument types. + \endrst + */ + BasicPrintfArgFormatter(BasicWriter &writer, FormatSpec &spec) + : internal::ArgFormatterBase(writer, spec) {} + /** Formats an argument of type ``bool``. */ void visit_bool(bool value) { FormatSpec &fmt_spec = this->spec(); if (fmt_spec.type_ != 's') @@ -193,6 +219,7 @@ class BasicPrintfArgFormatter : public ArgFormatterBase { this->write(value); } + /** Formats a character. */ void visit_char(int value) { const FormatSpec &fmt_spec = this->spec(); BasicWriter &w = this->writer(); @@ -215,6 +242,7 @@ class BasicPrintfArgFormatter : public ArgFormatterBase { *out = static_cast(value); } + /** Formats a null-terminated C string. */ void visit_cstring(const char *value) { if (value) Base::visit_cstring(value); @@ -224,6 +252,7 @@ class BasicPrintfArgFormatter : public ArgFormatterBase { this->write("(null)"); } + /** Formats a pointer. */ void visit_pointer(const void *value) { if (value) return Base::visit_pointer(value); @@ -231,7 +260,8 @@ class BasicPrintfArgFormatter : public ArgFormatterBase { write_null_pointer(); } - void visit_custom(Arg::CustomValue c) { + /** Formats an argument of a custom (user-defined) type. */ + void visit_custom(internal::Arg::CustomValue c) { BasicFormatter formatter(ArgList(), this->writer()); const Char format_str[] = {'}', 0}; const Char *format = format_str; @@ -248,11 +278,9 @@ class PrintfArgFormatter PrintfArgFormatter(BasicWriter &w, FormatSpec &s) : BasicPrintfArgFormatter, Char>(w, s) {} }; -} // namespace internal /** This template formats data and writes the output to a writer. */ -template > +template > class PrintfFormatter : private internal::FormatterBase { private: BasicWriter &writer_; diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index ef25895d..cc9c4485 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -10,7 +10,7 @@ #include "fmt/printf.h" #include "gtest-extra.h" -using fmt::internal::BasicPrintfArgFormatter; +using fmt::BasicPrintfArgFormatter; // A custom argument formatter that doesn't print `-` for floating-point values // rounded to 0. @@ -30,15 +30,18 @@ class CustomArgFormatter // A custom argument formatter that doesn't print `-` for floating-point values // rounded to 0. -class CustomPAF : public BasicPrintfArgFormatter { +class CustomPrintfArgFormatter : + public BasicPrintfArgFormatter { public: - CustomPAF(fmt::BasicWriter &writer, fmt::FormatSpec &spec) - : BasicPrintfArgFormatter(writer, spec) {} + typedef BasicPrintfArgFormatter Base; + + CustomPrintfArgFormatter(fmt::BasicWriter &w, fmt::FormatSpec &spec) + : Base(w, spec) {} void visit_double(double value) { if (round(value * pow(10, spec().precision())) == 0) value = 0; - BasicPrintfArgFormatter::visit_double(value); + Base::visit_double(value); } }; @@ -53,7 +56,7 @@ FMT_VARIADIC(std::string, custom_format, const char *) std::string custom_sprintf(const char* format_str, fmt::ArgList args){ fmt::MemoryWriter writer; - fmt::PrintfFormatter formatter(args, writer); + fmt::PrintfFormatter formatter(args, writer); formatter.format(format_str); return writer.str(); }