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