220 32865 <CANawtxZQEpgN7Uf_1+dCLDAtFT0DHKwfeAZjOwe8Y1jUdRKR2Q@mail.gmail.com> article
Path: news.gmane.org!.POSTED!not-for-mail
From: Victor Zverovich <victor.zverovich@gmail.com>
Newsgroups: gmane.comp.lang.c++.isocpp.proposals
Subject: Re: Re: C++ formatting library proposal
Date: Sat, 24 Jun 2017 18:52:37 +0000
Lines: 474
Approved: news@gmane.org
Message-ID: <CANawtxZQEpgN7Uf_1+dCLDAtFT0DHKwfeAZjOwe8Y1jUdRKR2Q@mail.gmail.com>
References: <CANawtxaVMmgecHONHp1HqsZTTzbVgnb_ZhqqPG4jxT++u4kjwg@mail.gmail.com>
 <e6e42f40-be11-46a4-824f-37199e9fa8da@isocpp.org> <4777755b-5984-4ef3-8fc5-a3e17aa94469@isocpp.org>
Reply-To: std-proposals@isocpp.org
NNTP-Posting-Host: blaine.gmane.org
Mime-Version: 1.0
Content-Type: multipart/alternative; boundary="94eb2c1959fe5106260552b939b5"
X-Trace: blaine.gmane.org 1498330370 27480 195.159.176.226 (24 Jun 2017 18:52:50 GMT)
X-Complaints-To: usenet@blaine.gmane.org
NNTP-Posting-Date: Sat, 24 Jun 2017 18:52:50 +0000 (UTC)
To: std-proposals@isocpp.org
Original-X-From: std-proposals+bncBCV6RYWKYEHBBAHKXLFAKGQEPF7BJ5Q@isocpp.org Sat Jun 24 20:52:45 2017
Return-path: <std-proposals+bncBCV6RYWKYEHBBAHKXLFAKGQEPF7BJ5Q@isocpp.org>
Envelope-to: gclcip-std-proposals@m.gmane.org
Original-Received: from mail-lf0-f70.google.com ([209.85.215.70])
	by blaine.gmane.org with esmtp (Exim 4.84_2)
	(envelope-from <std-proposals+bncBCV6RYWKYEHBBAHKXLFAKGQEPF7BJ5Q@isocpp.org>)
	id 1dOqAm-0006vv-Vg
	for gclcip-std-proposals@m.gmane.org; Sat, 24 Jun 2017 20:52:45 +0200
Original-Received: by mail-lf0-f70.google.com with SMTP id y194sf17446314lfd.11
        for <gclcip-std-proposals@m.gmane.org>; Sat, 24 Jun 2017 11:52:50 -0700 (PDT)
ARC-Seal: i=2; a=rsa-sha256; t=1498330370; cv=pass;
        d=google.com; s=arc-20160816;
        b=00nRksN6YJPrqlwt59hpH/kW5CzIgCXHPSzt9eO3YMykxWkIHcAlpfcB7Dc0hElQ4v
         VdW4r4BDG9JJ+X9NOdDCfiTCx7EyDqdSGUxinettgjXusZoQK7/gjivwKo5CrBc/uhZC
         uYTE23QperBB01dyo825I467/hpAY9UmIb0/Pkm6OqpgMBaOC7Y3BdHM3u9SmHys/1Wh
         vKjU5n+J6zgfiALHlrGDXTqmBMlA+afkRp0PO/d09NxMLWXS9umKXwXOAilaUZpWKdR4
         9c7WMAae2CQ+gva0Gm+odcF67bPdYs/ySRZM26RtyLftaFfeu/m8b5LG38Ap7NmKK89L
         DZZA==
ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post
         :list-id:mailing-list:precedence:reply-to:to:subject:message-id:date
         :from:in-reply-to:references:mime-version:arc-authentication-results
         :arc-message-signature:dkim-signature:arc-authentication-results;
        bh=+/6PkkYmaDZvsFyOwQu6DIun71293VMvSbuZEzFA6Xg=;
        b=h/vgDFTbzjbiOGQBoAVKuDAUl5k8kl9GldTacQRSW2IDKJPMlBkFHcL827cxdTf4FD
         wsT0sUOJxnIx1llLhMxqata3L7Xl+k65hGzXJk92s/Uolta72qPIWYaRXM7leOm2QVBM
         5ZhD9xRqB/GlCAvnmv23Y9hLl/Wo3fm2Qal2mj9xu7j03iHx1By6wEm3UO35+mVPtXHk
         7+MK7H8dl+Hw7W50M0PQZbjNWsMPCy+cn9t/nB+uFUpeMrlYOtd3GgSqPyjDrMKOkBeZ
         p1tTbiN2gqBuCAAsdgkxAEv1yt0XJQ55w5zunCg5UhxWOLlovffJuH3HoV2/cR4jaGey
         6Q1A==
ARC-Authentication-Results: i=2; mx.google.com;
       dkim=pass header.i=@gmail.com header.b=oxrL+2Vy;
       spf=pass (google.com: domain of victor.zverovich@gmail.com designates 2a00:1450:400c:c0c::232 as permitted sender) smtp.mailfrom=victor.zverovich@gmail.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmail.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=isocpp-org.20150623.gappssmtp.com; s=20150623;
        h=mime-version:references:in-reply-to:from:date:message-id:subject:to
         :x-original-sender:x-original-authentication-results:reply-to
         :precedence:mailing-list:list-id:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=+/6PkkYmaDZvsFyOwQu6DIun71293VMvSbuZEzFA6Xg=;
        b=G2einXmBw6rUdNv58PvGwct0mmqxxvowowk0/cCBdmnoc0XuXjMAzAUIOBPjS8mLef
         eRoMfTVAZcQlHzJa5/e3RhPIHjpwOLG4gSn9wWVxoDqOGdkxXAwfwCKO608p7gx8TKKy
         0VGLabg8yy4Y7+gW+WAWix8UtyDwZxxHuLIsjPlCtzIDtft5qlvChwUL8hRmWetZZOVu
         9y8WrfA4hIkG50I21Xu6tZGymY9iTl+bHcL2Lq4v1tb22ynxnmjo0JjDQS/SJ70O3TVX
         d1FXjtVpRgdDaGh0kncZer+0drHVAQ8+JMo+nTtkLC+ZZs2ZezXJOltBv2vHM61kAvPH
         XYPw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20161025;
        h=x-gm-message-state:mime-version:references:in-reply-to:from:date
         :message-id:subject:to:x-original-sender
         :x-original-authentication-results:reply-to:precedence:mailing-list
         :list-id:x-spam-checked-in-group:list-post:list-help:list-archive
         :list-subscribe:list-unsubscribe;
        bh=+/6PkkYmaDZvsFyOwQu6DIun71293VMvSbuZEzFA6Xg=;
        b=IJfbfrzirHp1qp6tQIv9+2Ldz4Epy8DCvNRCoTa0kLFzA1/+OqzTkS2jCsi3HF4fCH
         zQP2T0c87BsF4EJJ4q5Gc6imbdjAf8CLsK9xETMVkTMXjnj20DZN8nX2JheGxguJQHa1
         tGm6kIRonn5dsZ2IuTiyxyMTaN37F7XMzYx2E4Z2Exp0bUVO58/jV0uqTmmhA5k6t7o6
         gVO0R/GJdGwvNenSibJPBXoPDh9+4rcixMDFk8yN/St+U7TN9ah2SDvu8HQE6OPsyJyx
         N3kVI5M/PoTQNyAqBR1c/sfdxEsNRtilaHAz8BHl/p+fzt0ZBHqKZmmssLtTzdBN480x
         AkMA==
X-Gm-Message-State: AKS2vOzNxOwifIIU+BgHU6XgEQVKd5luSOQz/TPWTfqslVK07zM/J0xm
	vCKJh9gnZmgOQugv
X-Received: by 10.25.145.73 with SMTP id y9mr2249185lfj.22.1498330370355;
        Sat, 24 Jun 2017 11:52:50 -0700 (PDT)
X-BeenThere: std-proposals@isocpp.org
Original-Received: by 10.28.136.136 with SMTP id k130ls239472wmd.25.canary-gmail; Sat,
 24 Jun 2017 11:52:48 -0700 (PDT)
X-Received: by 10.223.171.83 with SMTP id r19mr9607006wrc.173.1498330368281;
        Sat, 24 Jun 2017 11:52:48 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1498330368; cv=none;
        d=google.com; s=arc-20160816;
        b=OtV0ROv59CxRAlhv9GcSSYg2nPN/Tku/0gUqZod2YG7HEohU3VxpgMA3ciWMkqDhcn
         DtxPAogfP7tLe9o2BMJOOtCplz1gBD7mbTlnPZdR61LMBBIYnlMLNFiNxetHWsdsqN90
         ptoesz+xrSqP3tjh8sQpLulGAG/JHMsxqXLlbInK+jJyBp3Fv0NzX6f66S10Y3PFdxJH
         jJmCDH+c7a0oYhjpv9w1hIUxg1DEqV7GUEGhUC08lBUiO4v2qIc03Dbt5hatpcakAXB1
         fHr7Y3JAKA8BBs2aL0GxkhVn9u7mZIooBin3m5gIXNeRP2RPx29+1yHTiXYrokv4jh40
         p7JA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=to:subject:message-id:date:from:in-reply-to:references:mime-version
         :dkim-signature:arc-authentication-results;
        bh=/aEhiUNqKt1Bhc52LByFHjD5gT+ecwEyuld3XrqgFTE=;
        b=nGMlGdGjjIpJjzT9/eZJEDS0bvV6DVIPtxkuBRsgt92mu4OuN7PiiBXn5jiBQpjh5a
         SUoRSpdRRPKaYeUK4vJ3rXIgaaixbF6ct7fPyEHSwFs6GPPUldeauAXowD3PCfit73Ie
         AIXPVG5Saa+at1q9ryD8Q2OB4PUzh/gxzMEpBFV++XaPjDHJJbvzzEtFPvP5HSXK0kC1
         tCJGaeTod3ry4N0Dm5IIr4Hj4Zwva+5pTyEr4vbFrrCtQQxWomvwmyCXTrITzRVT7dh1
         sdG5ZKy1jIWZSOuuDYr4YstkHP9MGdpAia6f6UuCnEKlk3kNTyzv32E5xIPb1sp8ouUg
         yqDg==
ARC-Authentication-Results: i=1; mx.google.com;
       dkim=pass header.i=@gmail.com header.b=oxrL+2Vy;
       spf=pass (google.com: domain of victor.zverovich@gmail.com designates 2a00:1450:400c:c0c::232 as permitted sender) smtp.mailfrom=victor.zverovich@gmail.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmail.com
Original-Received: from mail-wr0-x232.google.com (mail-wr0-x232.google.com. [2a00:1450:400c:c0c::232])
        by mx.google.com with ESMTPS id z199si6807154wmc.58.2017.06.24.11.52.48
        for <std-proposals@isocpp.org>
        (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
        Sat, 24 Jun 2017 11:52:48 -0700 (PDT)
Received-SPF: pass (google.com: domain of victor.zverovich@gmail.com designates 2a00:1450:400c:c0c::232 as permitted sender) client-ip=2a00:1450:400c:c0c::232;
Original-Received: by mail-wr0-x232.google.com with SMTP id c11so104179237wrc.3
        for <std-proposals@isocpp.org>; Sat, 24 Jun 2017 11:52:48 -0700 (PDT)
X-Received: by 10.80.140.2 with SMTP id p2mr10235354edp.129.1498330367589;
 Sat, 24 Jun 2017 11:52:47 -0700 (PDT)
In-Reply-To: <4777755b-5984-4ef3-8fc5-a3e17aa94469@isocpp.org>
X-Original-Sender: victor.zverovich@gmail.com
X-Original-Authentication-Results: mx.google.com;       dkim=pass
 header.i=@gmail.com header.b=oxrL+2Vy;       spf=pass (google.com: domain of
 victor.zverovich@gmail.com designates 2a00:1450:400c:c0c::232 as permitted
 sender) smtp.mailfrom=victor.zverovich@gmail.com;       dmarc=pass (p=NONE
 sp=NONE dis=NONE) header.from=gmail.com
Precedence: list
Mailing-list: list std-proposals@isocpp.org; contact std-proposals+owners@isocpp.org
List-ID: <std-proposals.isocpp.org>
X-Google-Group-Id: 399137483710
List-Post: <https://groups.google.com/a/isocpp.org/group/std-proposals/post>, <mailto:std-proposals@isocpp.org>
List-Help: <https://support.google.com/a/isocpp.org/bin/topic.py?topic=25838>, <mailto:std-proposals+help@isocpp.org>
List-Archive: <https://groups.google.com/a/isocpp.org/group/std-proposals/>
List-Subscribe: <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>,
 <mailto:std-proposals+subscribe@isocpp.org>
List-Unsubscribe: <mailto:googlegroups-manage+399137483710+unsubscribe@googlegroups.com>,
 <https://groups.google.com/a/isocpp.org/group/std-proposals/subscribe>
Xref: news.gmane.org gmane.comp.lang.c++.isocpp.proposals:32865
Archived-At: <http://permalink.gmane.org/gmane.comp.lang.c++.isocpp.proposals/32865>

--94eb2c1959fe5106260552b939b5
Content-Type: text/plain; charset="UTF-8"

> It would be nice if it was easy to create a formatting object from a
format specification string.

I think this is a great idea and I finally got a chance to experiment with
it.

The main drawback of having a separate formatting object is that it makes
writing a formatter for a user-defined type more complicated, because you
need to define 3 things: a formatter class, a parsing function and a
formatting function. In the current proposal everything is combined in
format_value which, on one hand, leads to less boilerplate but, on the
other hand, is more restrictive.

template <>
class formatter<MyClass> {
 public:
  explicit formatter(context &ctx) {
    // Parse the format string.
  }

  void format(buffer &buf, MyClass &value) {
    // Format value.
  }

 private:
  // Formatting state.
};

One way to reduce boilerplate is by returning the formatter object as a
lambda from the parsing function, e.g.

auto parse_format<MyClass>(context &ctx) {
  // Parse the format string.
  return [/* Formatting state */](buffer &buf, MyClass &value) {
    // Format value.
  };
}

Unfortunately this doesn't work if parse_format has to take additional
template arguments such as a char type:

// Doesn't compile
template <typename Char>
auto parse_format<MyClass>(basic_context<Char> &ctx) {
  // Parse the format string.
  return [/* Formatting state */](basic_buffer<Char> &buf, MyClass &value) {
    // Format value.
  };
}

A possible workaround is to use enable_if:

template <typename T, typename U>
using enable_format = typename std::enable_if<std::is_same<T,
U>::value>::type;

template <typename T, typename Char, typename = enable_format<T, MyClass>>
auto parse_format(basic_context<Char> &ctx) {
  // Parse the format string.
  return [/* Formatting state */](basic_buffer<Char> &buf, MyClass &value) {
    // Format value.
  };
}

This workaround does the job (implemented in experimental branch:
https://github.com/fmtlib/fmt/tree/ext) but I am not super happy about it.
Any ideas on how to improve this are appreciated.

Best regards,
Victor

On Tue, Jun 6, 2017 at 3:12 PM Bengt Gustafsson <
bengt.gustafsson@beamways.com> wrote:

> I like this functionality a lot, it has been sorely lacking in C++ and is
> becoming more and more a standard in many other languages.
>
> Some comments:
>
> - I would like the part before the : inside {} to allow any text. This
> allows translators to understand better the meaning of the inserted value
> and thus produce better translations. Not writing anything before the :
> would still
> be equivalent to writing the next consecutive number. I think you removed
> this capability from the python implementation as C++ does not have named
> arguments but it still has value in conveying information between
> programmer and the person doing translation.
>
> - Some kind of standard interface to internationalization string
> replacement could be incorporated in format(), so that we don't have to
> write _() or something around the literal.
>
> - How to specify using . for decimal char in a country where , is standard
> and vice versa. n only seems to relate to thousand separator handling, but
> the usual problem is to get the right decimal character in float number
> output. Many file formats (JSON for instance) require a dot even in
> countries where comma is standard. This is a recurring problem as "someone
> else" may set your locale on a  global level. I have a similar library
> where I use comma or dot (in the dot position in the format string) to
> denote themselves as decimal char while semicolon denotes "the locale
> decimal char". While creating your own buffer type which overrides the
> locale() method is possible it is much more work than defining the decimal
> char in the format string.
>
> - I don't particularly like the partial reuse of the C formatting
> conventions with a specified order of the parts of the format string, as it
> is hard to learn. Sure, it is rather easy whern you have learned printf,
> but do we want future generations of programmers have to go through that
> detour? Better start from scratch with something logical, where the order
> of characters is not crucial.
>
> - It may be better to send the formatting string snippet to format_value()
> as a basic_string_view rather than relying on all the function overloads to
> remember to bump the ptr correctly. At least provide a method in ctx to
> forward the ptr and return the basic_string_view containing the format part
> in case you want to preserve the possibility to nest {} inside the
> formatting string. This simplifies for the fairly large share of
> format_value functions which are implemented but don't care about any
> formatting details.
>
> - A maximum inserted length is often useful to limit the output. One case
> is when formatting large doubles in the f format. This can get ridiculous
> in printf. Another is potentially long file names, where you may want to
> limit the string length.
>
> - It is hard to understand the "arg store" idea and how this goes together
> with calling format_value on each parameter. It may be that the fmt::args
> and basic_args are actually the same. There is also arg_store and basic_arg
> and the visit() function which seem more like internal details of the
> implementation. Even as an implementation it seems overly complex, and I
> for one can't understand how visit can call separate user defined
> format_value functions if arg_store is not templated on the argument types.
>
> - It would be nice if it was easy to create a formatting object from a
> format specification string. This object should have methods to format the
> standard types that fomat() works for "out of the box". In this way you can
> easily override format_value for instance for std::vector<T>, passing each
> element to a formatting object you have created. Of course you can also
> call format_value() for each T provided it exists, but this incurs quite an
> overhead as the same format specification string is parsed over and over
> again for each array element. Taking this thought to the logical conclusion
> means that the customization point for a user defined type should be a
> function create_formatter<T>(string_view format_specification_string)
> rather than format_value. The formatter returned from create_formatter then
> has a method format(const T& value) which does the formatting job. This
> allows the vector optimization to be taken to vectors of vectors etc.
> Continuing on this tangent I think it may make sense to allow pre-creating
> a formatting object for an entire format string, so that the parsing of
> that string occurs only once. Lets call this class formatter<Ts...>.
> Example:
>
> template<typename... Ts> class formatter {
> public:
>     formatter(string_view format_string);  // This parses the
> format_string and stores the objects returned from create_formatter<T> for
> each of the Ts.
>
>     void run(buffer& buf, const Ts&.. args);    // Perform the formatting
> to a buffer
>     string run(buffer& buf, const Ts&... args); // Perform the formatting
> and return a string
> };
>
> // The format function is then defined as:
> template<typename... Ts> string format(string_view format_string, const
> Ts& values)
> {
>      formatter<Ts...> fmt(format_string);
>      return fmt.run(values...);
> }
> // A good compiler hopefully generates the same code as in the current
> implementation.
> // A loop for printing many lines would be more effective if written:
>
> formatter<int, string, double> fmt("#{IX}: {NAME}, {PRICE:.2");   //
> Preparse format
> for (item : inventory)
>     cout << fmt.run(item.ix, item.name, item.price);
>
>
>
>
>
>
>
>
>
> Den tisdag 6 juni 2017 kl. 16:04:37 UTC+2 skrev Nicol Bolas:
>>
>> On Tuesday, June 6, 2017 at 9:41:26 AM UTC-4, Victor Zverovich wrote:
>>>
>>> I'm working on a proposal for a new formatting functionality for the C++
>>> standard library based on the fmt library (https://github.com/fmtlib/fmt
>>> ).
>>>
>>> The first draft of the proposal is available at
>>> http://fmtlib.net/Text%20Formatting.html and I would appreciate any
>>> comments.
>>>
>>> - Victor
>>>
>>
>> I'm concerned about this:
>>
>> The formatting library uses a null-terminated string view
>>> basic_cstring_view instead of basic_string_view. This results in
>>> somewhat smaller and faster code because the string size, which is not
>>> used, doesn't have to be computed and passed. Also having a termination
>>> character makes parsing easier.
>>>
>>
>> This really hurts users of `basic_string_view`, since their views are
>> *not* NUL-terminated. Such users don't necessarily have to calculate the
>> string size either; the `sv` user-defined literal will generate the size
>> based on the input literal.
>>
>> Your insistence on `basic_cstring_view` only aids scenarios where the
>> user has an unsized, NUL-terminated string. So they would have to not be
>> using `basic_string` or similar types (which are sized).
>>
> --
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/4777755b-5984-4ef3-8fc5-a3e17aa94469%40isocpp.org
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/4777755b-5984-4ef3-8fc5-a3e17aa94469%40isocpp.org?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANawtxZQEpgN7Uf_1%2BdCLDAtFT0DHKwfeAZjOwe8Y1jUdRKR2Q%40mail.gmail.com.

--94eb2c1959fe5106260552b939b5
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">&gt;=C2=A0<span style=3D"color:rgb(33,33,33);font-size:13p=
x">It would be nice if it was easy to create a formatting object from a for=
mat specification string.</span><div><font color=3D"#212121"><br></font></d=
iv><div><font color=3D"#212121">I think this is a great idea and I finally =
got a chance to experiment with it.=C2=A0</font></div><div><font color=3D"#=
212121"><br></font></div><div><font color=3D"#212121">The main drawback of =
having a separate formatting object is that it makes writing a formatter fo=
r a user-defined type more complicated, because you need to define 3 things=
: a formatter class, a parsing function and a formatting function.=C2=A0</f=
ont><span style=3D"color:rgb(33,33,33)">In the current proposal everything =
is combined in format_value which, on one hand, leads to less boilerplate b=
ut, on the other hand, is more restrictive.</span></div><div><span style=3D=
"color:rgb(33,33,33)"><br></span></div><div><span style=3D"color:rgb(33,33,=
33)">template &lt;&gt;</span></div><div><font color=3D"#212121">class forma=
tter&lt;MyClass&gt; {</font></div><div><font color=3D"#212121">=C2=A0public=
:</font></div><div><font color=3D"#212121">=C2=A0 explicit formatter(contex=
t &amp;ctx) {</font></div><div><font color=3D"#212121">=C2=A0 =C2=A0 // Par=
se the format string.</font></div><div><font color=3D"#212121">=C2=A0 }</fo=
nt></div><div><font color=3D"#212121"><br></font></div><div><font color=3D"=
#212121">=C2=A0 void format(</font><span style=3D"color:rgb(33,33,33)">buff=
er &amp;buf, MyClass &amp;value) {</span></div><div><span style=3D"color:rg=
b(33,33,33)">=C2=A0 =C2=A0=C2=A0</span><span style=3D"color:rgb(33,33,33)">=
// Format value.</span></div><div><span style=3D"color:rgb(33,33,33)">=C2=
=A0 }</span></div><div><font color=3D"#212121"><br></font></div><div><font =
color=3D"#212121">=C2=A0private:</font></div><div><font color=3D"#212121">=
=C2=A0 // Formatting state.</font></div><div><font color=3D"#212121">};</fo=
nt></div><div><font color=3D"#212121"><br></font></div><div><font color=3D"=
#212121">One way to reduce boilerplate is by returning the formatter object=
 as a lambda from the parsing function, e.g.</font></div><div><br></div><di=
v><font color=3D"#212121">auto parse_format&lt;MyClass&gt;(context &amp;ctx=
) {</font></div><div><font color=3D"#212121">=C2=A0 // Parse the format str=
ing.</font></div><div><font color=3D"#212121">=C2=A0 return [/* Formatting =
state */](buffer &amp;buf, MyClass &amp;value) {</font></div><div><font col=
or=3D"#212121">=C2=A0 =C2=A0 // Format value.</font></div><div><font color=
=3D"#212121">=C2=A0 };</font></div><div><font color=3D"#212121">}</font></d=
iv><div><br></div><div><font color=3D"#212121">Unfortunately this doesn&#39=
;t work if=C2=A0</font><span style=3D"color:rgb(33,33,33)">parse_format has=
 to take additional template arguments such as a char type:</span></div><di=
v><span style=3D"color:rgb(33,33,33)"><br></span></div><div><span style=3D"=
color:rgb(33,33,33)">// Doesn&#39;t compile</span></div><div><span style=3D=
"color:rgb(33,33,33)">template &lt;typename Char&gt;</span></div><div><div>=
<font color=3D"#212121">auto parse_format&lt;MyClass&gt;(basic_context&lt;C=
har&gt; &amp;ctx) {</font></div><div><font color=3D"#212121">=C2=A0 // Pars=
e the format string.</font></div><div><font color=3D"#212121">=C2=A0 return=
 [/*=C2=A0</font><span style=3D"color:rgb(33,33,33)">Formatting state</span=
><font color=3D"#212121">=C2=A0*/](basic_buffer&lt;Char&gt; &amp;buf, MyCla=
ss &amp;value) {</font></div><div><font color=3D"#212121">=C2=A0 =C2=A0 // =
Format value.</font></div><div><font color=3D"#212121">=C2=A0 };</font></di=
v><div><font color=3D"#212121">}</font></div></div><div><font color=3D"#212=
121"><br></font></div><div><font color=3D"#212121">A possible workaround is=
 to use enable_if:</font></div><div><font color=3D"#212121"><br></font></di=
v><div><font color=3D"#212121"><div>template &lt;typename T, typename U&gt;=
</div><div>using enable_format =3D typename std::enable_if&lt;std::is_same&=
lt;T, U&gt;::value&gt;::type;</div><div><br></div><div><div style=3D"color:=
rgb(0,0,0)"><span style=3D"color:rgb(33,33,33)">template &lt;typename T, ty=
pename Char, typename =3D enable_format&lt;T, MyClass&gt;&gt;</span></div><=
div style=3D"color:rgb(0,0,0)"><div><font color=3D"#212121">auto parse_form=
at(basic_context&lt;Char&gt; &amp;ctx) {</font></div><div><font color=3D"#2=
12121">=C2=A0 // Parse the format string.</font></div><div><font color=3D"#=
212121">=C2=A0 return [/*=C2=A0</font><span style=3D"color:rgb(33,33,33)">F=
ormatting state</span><font color=3D"#212121">=C2=A0*/](basic_buffer&lt;Cha=
r&gt; &amp;buf, MyClass &amp;value) {</font></div><div><font color=3D"#2121=
21">=C2=A0 =C2=A0 // Format value.</font></div><div><font color=3D"#212121"=
>=C2=A0 };</font></div><div><font color=3D"#212121">}</font></div><div><fon=
t color=3D"#212121"><br></font></div><div><font color=3D"#212121">This work=
around does the job (implemented in experimental branch:=C2=A0</font><a hre=
f=3D"https://github.com/fmtlib/fmt/tree/ext">https://github.com/fmtlib/fmt/=
tree/ext</a><span style=3D"color:rgb(33,33,33)">)</span><span style=3D"colo=
r:rgb(33,33,33)">=C2=A0but I am not super happy about it. Any ideas on how =
to improve this are appreciated.</span></div><div><span style=3D"color:rgb(=
33,33,33)"><br></span></div><div><span style=3D"color:rgb(33,33,33)">Best r=
egards,</span></div><div><span style=3D"color:rgb(33,33,33)">Victor</span><=
/div></div></div></font></div><div><br><div class=3D"gmail_quote"><div dir=
=3D"ltr">On Tue, Jun 6, 2017 at 3:12 PM Bengt Gustafsson &lt;<a href=3D"mai=
lto:bengt.gustafsson@beamways.com">bengt.gustafsson@beamways.com</a>&gt; wr=
ote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;=
border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>I like t=
his functionality a lot, it has been sorely lacking in C++ and is becoming =
more and more a standard in many other languages.</div><div><br></div><div>=
Some comments:<br></div><div><br></div><div>- I would like the part before =
the : inside {} to allow any text. This allows translators to understand be=
tter the meaning of the inserted value and thus produce better translations=
.. Not writing anything before the : would still</div><div>be equivalent to =
writing the next consecutive number. I think you removed this capability fr=
om the python implementation as C++ does not have named arguments but it st=
ill has value in conveying information between programmer and the person do=
ing translation.</div><div><br></div><div>- Some kind of standard interface=
 to internationalization string replacement could be incorporated in format=
(), so that we don&#39;t have to write _() or something around the literal.=
</div><div><br></div><div>- How to specify using . for decimal char in a co=
untry where , is standard and vice versa. n only seems to relate to thousan=
d separator handling, but the usual problem is to get the right decimal cha=
racter in float number output. Many file formats (JSON for instance) requir=
e a dot even in countries where comma is standard. This is a recurring prob=
lem as &quot;someone else&quot; may set your locale on a =C2=A0global level=
.. I have a similar library where I use comma or dot (in the dot position in=
 the format string) to denote themselves as decimal char while semicolon de=
notes &quot;the locale decimal char&quot;. While creating your own buffer t=
ype which overrides the locale() method is possible it is much more work th=
an defining the decimal char in the format string.</div><div><br></div><div=
>- I don&#39;t particularly like the partial reuse of the C formatting conv=
entions with a specified order of the parts of the format string, as it is =
hard to learn. Sure, it is rather easy whern you have learned printf, but d=
o we want future generations of programmers have to go through that detour?=
 Better start from scratch with something logical, where the order of chara=
cters is not crucial.</div><div><br></div><div>- It may be better to send t=
he formatting string snippet to format_value() as a basic_string_view rathe=
r than relying on all the function overloads to remember to bump the ptr co=
rrectly. At least provide a method in ctx to forward the ptr and return the=
 basic_string_view containing the format part in case you want to preserve =
the possibility to nest {} inside the formatting string. This simplifies fo=
r the fairly large share of format_value functions which are implemented bu=
t don&#39;t care about any formatting details.</div><div><br></div><div>- A=
 maximum inserted length is often useful to limit the output. One case is w=
hen formatting large doubles in the f format. This can get ridiculous in pr=
intf. Another is potentially long file names, where you may want to limit t=
he string length.</div><div><br></div><div>- It is hard to understand the &=
quot;arg store&quot; idea and how this goes together with calling format_va=
lue on each parameter. It may be that the fmt::args and basic_args are actu=
ally the same. There is also arg_store and basic_arg and the visit() functi=
on which seem more like internal details of the implementation. Even as an =
implementation it seems overly complex, and I for one can&#39;t understand =
how visit can call separate user defined format_value functions if arg_stor=
e is not templated on the argument types.</div><div><br></div><div>- It wou=
ld be nice if it was easy to create a formatting object from a format speci=
fication string. This object should have methods to format the standard typ=
es that fomat() works for &quot;out of the box&quot;. In this way you can e=
asily override format_value for instance for std::vector&lt;T&gt;, passing =
each element to a formatting object you have created. Of course you can als=
o call format_value() for each T provided it exists, but this incurs quite =
an overhead as the same format specification string is parsed over and over=
 again for each array element. Taking this thought to the logical conclusio=
n means that the customization point for a user defined type should be a fu=
nction create_formatter&lt;T&gt;(string_view format_specification_string) r=
ather than format_value. The formatter returned from create_formatter then =
has a method format(const T&amp; value) which does the formatting job. This=
 allows the vector optimization to be taken to vectors of vectors etc. Cont=
inuing on this tangent I think it may make sense to allow pre-creating a fo=
rmatting object for an entire format string, so that the parsing of that st=
ring occurs only once. Lets call this class formatter&lt;Ts...&gt;. Example=
:</div><div><br></div><div>template&lt;typename... Ts&gt; class formatter {=
</div><div>public:</div><div>=C2=A0 =C2=A0 formatter(string_view format_str=
ing); =C2=A0// This parses the format_string and stores the objects returne=
d from create_formatter&lt;T&gt; for each of the Ts.</div><div><br></div><d=
iv>=C2=A0 =C2=A0 void run(buffer&amp; buf, const Ts&amp;.. args); =C2=A0 =
=C2=A0// Perform the formatting to a buffer</div><div>=C2=A0 =C2=A0 string =
run(buffer&amp; buf, const Ts&amp;... args); // Perform the formatting and =
return a string</div><div>};</div><div><br></div><div>// The format functio=
n is then defined as:</div><div>template&lt;typename... Ts&gt; string forma=
t(string_view format_string, const Ts&amp; values)</div><div>{</div><div>=
=C2=A0 =C2=A0 =C2=A0formatter&lt;Ts...&gt; fmt(format_string);</div><div>=
=C2=A0 =C2=A0 =C2=A0return fmt.run(values...);</div><div>}</div><div>// A g=
ood compiler hopefully generates the same code as in the current implementa=
tion.</div><div>// A loop for printing many lines would be more effective i=
f written:</div><div><br></div><div>formatter&lt;int, string, double&gt; fm=
t(&quot;#{IX}: {NAME}, {PRICE:.2&quot;); =C2=A0 // Preparse format</div><di=
v>for (item : inventory)</div><div>=C2=A0 =C2=A0 cout &lt;&lt; fmt.run(item=
..ix, <a href=3D"http://item.name" target=3D"_blank">item.name</a>, item.pri=
ce);</div></div><div dir=3D"ltr"><div><br></div><div><br></div><div><br></d=
iv><div><br></div><div><br></div><div><br></div><div><br></div><div><br><br=
>Den tisdag 6 juni 2017 kl. 16:04:37 UTC+2 skrev Nicol Bolas:<blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #cc=
c solid;padding-left:1ex"><div dir=3D"ltr">On Tuesday, June 6, 2017 at 9:41=
:26 AM UTC-4, Victor Zverovich wrote:<blockquote class=3D"gmail_quote" styl=
e=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex=
"><div dir=3D"ltr"><div><span style=3D"font-size:13px;color:rgb(33,33,33)">=
I&#39;m working on a proposal for a new formatting functionality for the C+=
+ standard library </span><span style=3D"color:rgb(33,33,33)"><span>based o=
n the fmt library (</span></span><font color=3D"#212121"><a href=3D"https:/=
/github.com/fmtlib/fmt" rel=3D"nofollow" target=3D"_blank">https://github.c=
om/fmtlib/fmt</a>).</font><br></div><div><span style=3D"font-size:13px;colo=
r:rgb(33,33,33)"><span><br></span></span></div><div><span style=3D"font-siz=
e:13px;color:rgb(33,33,33)"><span>The first draft of the proposal is availa=
ble at=C2=A0</span></span><a href=3D"http://fmtlib.net/Text%20Formatting.ht=
ml" style=3D"font-size:13px" rel=3D"nofollow" target=3D"_blank">http://fmtl=
ib.net/Text%20Formatting.html</a><font color=3D"#212121">=C2=A0and I would =
appreciate any comments.</font></div><div><font color=3D"#212121"><br></fon=
t></div><div><font color=3D"#212121">- Victor</font></div></div></blockquot=
e><div><br>I&#39;m concerned about this:<br><br><blockquote class=3D"gmail_=
quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,=
204);padding-left:1ex">The formatting library uses a null-terminated string=
 view
<code>basic_cstring_view</code> instead of <code>basic_string_view</code>.
This results in somewhat smaller and faster code because the string size,
which is not used, doesn&#39;t have to be computed and passed. Also having
a termination character makes parsing easier. <br></blockquote><div><br>Thi=
s really hurts users of `basic_string_view`, since their views are <i>not</=
i> NUL-terminated. Such users don&#39;t necessarily have to calculate the s=
tring size either; the `sv` user-defined literal will generate the size bas=
ed on the input literal.<br><br>Your insistence on `basic_cstring_view` onl=
y aids scenarios where the user has an unsized, NUL-terminated string. So t=
hey would have to not be using `basic_string` or similar types (which are s=
ized).<br></div></div></div></blockquote></div></div>

<p></p>

-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_=
blank">std-proposals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/4777755b-5984-4ef3-8fc5-a3e17aa94469%=
40isocpp.org?utm_medium=3Demail&amp;utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/4777755b-5984-=
4ef3-8fc5-a3e17aa94469%40isocpp.org</a>.<br>
</blockquote></div></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CANawtxZQEpgN7Uf_1%2BdCLDAtFT0DHKwfeA=
ZjOwe8Y1jUdRKR2Q%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANawtxZQEpgN7U=
f_1%2BdCLDAtFT0DHKwfeAZjOwe8Y1jUdRKR2Q%40mail.gmail.com</a>.<br />

--94eb2c1959fe5106260552b939b5--

.
