diff --git a/cppformat/format.h b/cppformat/format.h index ccd928fc..bb73a54c 100644 --- a/cppformat/format.h +++ b/cppformat/format.h @@ -380,7 +380,8 @@ template -void format(BasicFormatter &f, const Char *&format_str, const T &value); +void format(BasicFormatter &f, + const Char *&format_str, const T &value); /** \rst @@ -1310,7 +1311,7 @@ struct NamedArg : Arg { // To use ArgVisitor define a subclass that implements some or all of the // visit methods with the same signatures as the methods in ArgVisitor, // for example, visit_int(int). -// Specify the subclass name as the Impl template parameter. Then calling +// Pass the subclass as the Impl template parameter. Then calling // ArgVisitor::visit for some argument will dispatch to a visit method // specific to the argument type. For example, if the argument type is // double then visit_double(double) method of a subclass will be called. @@ -1907,7 +1908,55 @@ class PrintfFormatter : private FormatterBase { }; } // namespace internal -// An argument formatter. +/** + \rst + An argument formatter. + To use `~fmt::BasicArgFormatter` define a subclass that implements some or all + of the visit methods with the same signatures as the methods in `ArgVisitor`, + for example, `visit_int(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 `visit_double(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::BasicArgFormatter` or its superclass will be + called. + + **Example**:: + + // A custom argument formatter that formats negative integers as unsigned + // with the ``x`` format specifier. + class CustomArgFormatter : + public fmt::BasicArgFormatter { + public: + CustomArgFormatter(fmt::BasicFormatter &f, + fmt::FormatSpec &s, const char *fmt) + : fmt::BasicArgFormatter(f, s, fmt) {} + + void visit_int(int value) { + fmt::FormatSpec &spec = this->spec(); + if (spec.type() == 'x') + visit_uint(value); // convert to unsigned and format + else + fmt::BasicArgFormatter::visit_int(value); + } + }; + + std::string custom_format(const char *format_str, fmt::ArgList args) { + fmt::MemoryWriter writer; + // Pass custom argument formatter to BasicFormatter. + fmt::BasicFormatter formatter(args, writer); + formatter.format(format_str); + return writer.str(); + } + FMT_VARIADIC(std::string, custom_format, const char *) + + std::string s = custom_format("{:x}", -42); // s == "ffffffd6" + + `~fmt::BasicArgFormatter` uses the `curiously recurring template pattern + `_. + \endrst + */ template class BasicArgFormatter : public internal::ArgFormatterBase { private: @@ -1915,20 +1964,23 @@ class BasicArgFormatter : public internal::ArgFormatterBase { const Char *format_; public: + /** Constructs an argument formatter object. */ BasicArgFormatter(BasicFormatter &f, FormatSpec &s, const Char *fmt) : internal::ArgFormatterBase(f.writer(), s), formatter_(f), format_(fmt) {} + /** Formats argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { c.format(&formatter_, c.value, &format_); } }; -// The default argument formatter. +/** The default argument formatter. */ template class ArgFormatter : public BasicArgFormatter, Char> { public: + /** Constructs an argument formatter object. */ ArgFormatter(BasicFormatter &f, FormatSpec &s, const Char *fmt) : BasicArgFormatter, Char>(f, s, fmt) {} }; diff --git a/doc/api.rst b/doc/api.rst index 07c1ec97..95e558ae 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -39,6 +39,15 @@ arguments in the resulting string. .. doxygenclass:: fmt::BasicFormatter :members: +Argument formatters +------------------- + +.. doxygenclass:: fmt::BasicArgFormatter + :members: + +.. doxygenclass:: fmt::ArgFormatter + :members: + Printf formatting functions --------------------------- diff --git a/doc/conf.py b/doc/conf.py index 43452c2d..d35a2fdf 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -76,7 +76,7 @@ copyright = u'2012-2015, Victor Zverovich' exclude_patterns = ['virtualenv'] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +default_role = 'cpp:any' # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True