From 3a663dff345b272518caf2e0879064039102696c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 23 Sep 2018 08:18:11 -0700 Subject: [PATCH] Argument visitation section --- Text Formatting.html | 67 ++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/Text Formatting.html b/Text Formatting.html index d79f22de..d5dd1c79 100644 --- a/Text Formatting.html +++ b/Text Formatting.html @@ -662,7 +662,7 @@

Compile-time processing of format strings T if the formatter<T>::parse function is constexpr. -

Argument visitation API

+

Argument visitation

The argument visitation API can be used to implement dynamic format specifiers, for example, width and precision passed as additional formatting @@ -680,43 +680,48 @@

Argument visitation API

struct Answer {}; template <> -struct formatter<Answer> { - int width_arg_index = 0; - - // Parses dynamic width in the format "{<digit>}". - auto parse(parse_context& parse_ctx) { - auto iter = parse_ctx.begin(); - auto get_char = [&]() { return iter != parse_ctx.end() ? *iter : 0; }; - - if (get_char() != '{') - return iter; - ++iter; - char c = get_char(); - if (!std::isdigit(c) || (++iter, get_char()) != '}') - throw format_error("invalid format"); - width_arg_index = c - '0'; - return ++iter; - } + struct formatter<Answer> { + int width_arg_index = 0; + + // Parses dynamic width in the format "{<digit>}". + auto parse(parse_context& parse_ctx) { + auto iter = parse_ctx.begin(); + auto get_char = [&]() { return iter != parse_ctx.end() ? *iter : 0; }; + + if (get_char() != '{') + return iter; + ++iter; + char c = get_char(); + if (!std::isdigit(c) || (++iter, get_char()) != '}') + throw format_error("invalid format"); + width_arg_index = c - '0'; + return ++iter; + } - auto format(Answer, format_context& format_ctx) { - format_arg arg = format_ctx.args().get(width_arg_index); - int width = visit([](auto value) -> int { - if constexpr (std::is_integral_v) - return value; - else - throw format_error("width is not integral"); - }, arg); - return format_to(format_ctx.out(), "{:{}}", 42, width); - } -}; + auto format(Answer, format_context& format_ctx) { + auto arg = format_ctx.args().get(width_arg_index); + int width = visit([](auto value) -> int { + if constexpr (!std::is_integral_v<decltype(value)>) + throw format_error("width is not integral"); + else if (value < 0 || value > std::numeric_limits<int>::max()) + throw format_error("invalid width"); + else + return value; + }, arg); + return format_to(format_ctx.out(), "{:{}}", 42, width); + } + }; + +std::string s = format("{0:{1}}", Answer(), 10); +// s == " 42"

In many cases formatting can be delegated to standard formatters which makes manual handling of dynamic specifiers unneccessary, but the latter is still important for more complex cases.

This API can also be used to implement a custom formatting engine, such as -the one compatible with the printf syntax, to simplify migration -from legacy formatting methods.

+the one compatible with the printf syntax, to provide some of the +benefits of the current proposal to the legacy code.

Impact on existing code