Я начал изучать C++, и то, что казалось простой задачей, оказалось большой головной болью.
Я заметил, что символ Юникода в моем форматировании съедает часть ширины столбца. Более того, когда я готовил минимальный воспроизводимый пример для этого вопроса, я заметил, что чем больше символов я добавляю, тем больше ширины съедается.
#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;
}
В результате чего
|Constant |Approximate value |
|p | 3.14159|
|π | 3.14159|
|ππ | 3.14159|
|πππ | 3.14159|
Я был бы очень признателен за ваше объяснение механизма этого явления. Кстати, интерактивный пример можно найти здесь: https://godbolt.org/z/s9Mf7KPYz
@Супер-интеллектуальный Шейд, большое спасибо! Звучит разумно. Есть ли способ надежно преодолеть этот эффект?
FWIW clang + stdlibc++ работает нормально, если вам подходит такой вариант: godbolt.org/z/cMq8Gehq4
Хм... транк gcc тоже работает: godbolt.org/z/dcMej1YKP
Я ожидаю, что это будет зависеть от настроек вашего региона.
@Super-intelligentShade Я считаю, что он должен поддерживать Юникод.





Обновлено: Я только что дважды проверил, и я действительно ошибаюсь. Поскольку аргумент не является ни числом с плавающей запятой, ни целым числом, выравнивание по левому краю должно быть значением по умолчанию.
Должно быть, это ошибка компилятора, поскольку простое изменение версии компилятора давало правильный результат.
{0:30} означает, что после переменной 0 будут стоять 30 пробелы.
Чтобы разделитель (|) был выровнен, вы можете использовать {0:<30}:
std::format("|{0:<30}|{1:30.5f}|\n", "p", std::numbers::pi)
Чтобы выровнять переменную 0 по левому краю и добавить отступы, чтобы длина строки была 30. (cppreference)
Живите в Compiler Explorer.
Потому что
std::formatне поддерживает Юникод и думает, что π — это два символа с кодами 0x03 и 0xc0. Но когда ваш терминал, поддерживающий Юникод, отображает его, он рисует один символ.