C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Width Formatting using std::format with custom locale [user defined do_get_separator()]

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Sun, 31 Mar 2024 09:55:40 +0000
On Sun, 31 Mar 2024 at 10:42, David Armour via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> I encountered an issue using std::format to format numbers which I
> wanted to have a custom comma thousand separator in the display.
>
> When using the customised locale with MSVC I discovered the added commas
> pushed the formatted number to the right making the number no longer
> conform to the width specifier.
>
> I tested the same code with GCC and found std::format() to conform
> correctly.
>
> I also tested both MSVC and GCC using std::cout.imbue() to make the
> stream format the numbers to my custom locale. In this instance it
> worked correctly on both compilers.
>
> I tried to find some info about this problem and it seems that for
> streams, the standard requires the use of std::setw() to include the
> custom locale but for std::format it is left to the compiler implementers.
>

Why did you conclude that?

It seems obvious to me that any digit separators inserted for a
locale-specific form should be included in the estimated field width.

"The estimated field width is the number of field width units that are
required for the formatted sequence of characters produced for a format
argument independent of the effects of the width option."




> I would suggest that the standard forces the same requirement to manage
> the custom locale in the width specifier for std::format as well as for
> imbue() on streams.
>

I think it already requires the behaviour you expect. If MSVC doesn't count
digit separators in the estimated field width, that seems like a bug.



>
> A code sample that reproduces the problem is found below. As mentioned,
> this needs to be compiled on MSVC to see the problem. I have not tested
> any other compilers to see if they have the same behaviour as MSVC.
>
>
> ********* CODE BELOW *********
> #include <format>
> #include <iomanip>
> #include <iostream>
> #include <locale>
>
> class MyNumPunct : public std::numpunct<char>
> {
> protected:
> char do_thousands_sep() const override
> {
> return ',';
> }
> std::string do_grouping() const override
> {
> return "\03";
> }
> };
>
> int main()
> {
> double dblValue1 = 1000.0;
> double dblValue2 = 1000000.0;
>
> // This is used as a ruler to easily see if the formatting is correct.
> std::cout <<
> "123456789012345678901234567890123456789012345678901234567890" <<
> std::endl;
>
> // Standard locale
> std::cout << std::format("{:20.2f}{:20.2f}", dblValue1, dblValue2) <<
> std::endl;
>
> // Custom locale with thousands separator.
> // Error in formatting. Numbers are pushed to the right by the commas.
> std::cout << std::format(std::locale(std::locale(""), new
> MyNumPunct), "{:20.2Lf}{:20.2Lf}", dblValue1, dblValue2) << std::endl;
>
> std::cout.imbue(std::locale(std::locale(""), new MyNumPunct));
> std::cout << std::fixed << std::setprecision(2) << std::setw(20) <<
> dblValue1 << std::setw(20) << dblValue2 << std::endl;
> return 0;
> }
>
> ******* CODE ENDS *******
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2024-03-31 09:57:03