C++ Logo

std-proposals

Advanced search

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

From: David Armour <dave.armour_at_[hidden]>
Date: Sun, 31 Mar 2024 17:41:00 +0800
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.

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.

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 *******

Received on 2024-03-31 09:41:05