Search code examples
c++c++20stdformat

unicode symbol breaks formatting in c++20


I started learning c++ and what seemed to be a piece of cake task turned out to be a big headache.

I noticed than a unicode symbol in my formatting eats a piece of column width. Even more when I was preparing a minimal reproducible example for this question I noted that the more symbols I add, the more width is eaten.

#include <iostream>
#include <format>

int main (int argc, char *argv[]) {
  std::cout << std::format("|{0:30}|{1:30}|\n", "Constant", "Approximate value");
  std::cout << std::format("|{0:30}|{1:30.5f}|\n", "p", std::numbers::pi);
  std::cout << std::format("|{0:30}|{1:30.5f}|\n", "π", std::numbers::pi);
  std::cout << std::format("|{0:30}|{1:30.5f}|\n", "ππ", std::numbers::pi);
  std::cout << std::format("|{0:30}|{1:30.5f}|\n", "πππ", std::numbers::pi);
  return 0;
}

Resulting in

|Constant                      |Approximate value             |
|p                             |                       3.14159|
|π                            |                       3.14159|
|ππ                          |                       3.14159|
|πππ                        |                       3.14159|

I would really appreciate your explanation of what the mechanism is behind this phenomenon. BTW please find the interactive example here: https://godbolt.org/z/s9Mf7KPYz


Solution

  • EDIT: I just double checked, and I'm actually wrong. Since the argument is neither a floating point number nor an integer, the left alignment should be the default.
    This had to be a compiler bug since simply changing the compiler version gave the right output.

    {0:30} means that the variable 0 will be followed by 30 spaces.
    For the separator (|) to be alined you can use {0:<30}:

    std::format("|{0:<30}|{1:30.5f}|\n", "p", std::numbers::pi)
    

    To align the variable 0 left and add padding so that the length of the line is 30. (cppreference)

    Live on Compiler Explorer.