У меня есть следующий фрагмент кода, который использует ширину, определенную во время выполнения:
#include <string>
#include <vector>
#include <fmt/core.h>
#include <fmt/format.h>
int main()
{
std::vector<std::string> lines =
{
"line 1 - xxxxxxxx",
"line 2 - xxxxxxxx",
"line 3 - xxxxxxxx",
"line 4 - xxxxxxxx",
};
const std::size_t width = 3;
for (std::size_t i = 0; i < lines.size(); ++i)
{
const auto& line = lines[i];
fmt::println("{:0{width}} {}",
i, fmt::arg("width",width),
line);
}
return 0;
}
Я ожидаю, что он выведет строки следующим образом, добавляя к каждой строке номер строки, выровненный по правому краю и дополненный цифрой «0».
000 line 1 - xxxxxxxx
001 line 2 - xxxxxxxx
002 line 3 - xxxxxxxx
003 line 4 - xxxxxxxx
Однако когда я запускаю его, я получаю следующее исключение во время выполнения:
Program returned: 139
libc++abi: terminating due to uncaught exception of type fmt::v11::format_error: cannot switch from manual to automatic argument indexing
Program terminated with signal: SIGSEGV
Я не уверен, где я ошибаюсь, я использую синтаксис, подробно описанный в разделе «Ширина, определяемая аргументами» отсюда:
https://hackingcpp.com/cpp/libs/fmt.html
Ссылка на Годболта: https://godbolt.org/z/fzv66KGe1
@user12002570 user12002570 Невозможно использовать функции формата std, поскольку кодовая база — C++20. Кроме того, я не думаю, что то, что доступно в C++23, позволяет использовать спецификаторы формата во время выполнения.
Вам следует добавить тег c++20.
Примечание: почему вы не ссылаетесь на собственную документацию fmt? (fmt.dev/11.0/api).
@PennyDreudter C++20/23 поддерживает аргументы во время выполнения. Он просто не поддерживает именованные аргументы, вам нужны аргументы на основе индекса (позиционные).
Я нигде не могу найти это задокументировано, но похоже, что вы не можете смешивать автоматические аргументы с именованными или индексированными аргументами, вы можете сделать следующее:
"{0:0{width}} {2}"
Или
"{:0{}} {}"
std::format документирует это ограничение:
указывает индекс аргумента в args, значение которого будет использоваться для форматирования; если он опущен, аргументы используются по порядку.
Идентификаторы аргументов в строке формата должны присутствовать все или быть опущены. Смешение ручной и автоматической индексации является ошибкой.
Вам следует добавить живую демо-версию (godbolt), по крайней мере, поскольку у нас нет официального источника для этого, поэтому, если в будущем что-то изменится, у нас будет ссылка на демо-версию, которая показывает эту работу.
Смешение ручной и автоматической индексации является ошибкой только для версии времени компиляции. Для версии времени выполнения, как и в вопросе ОП, их можно смешивать с тем ограничением, что вы не можете переключаться с ручного на автоматический. Итак, в случае OP {:0{width}} {2}", i, fmt::arg("width",width), line);
работает нормально (где нужно указать только 2, поскольку ему предшествует ручной индекс с width
). godbolt.org/z/cWrP7vfKj Не знаю, почему существует несоответствие между версиями времени выполнения и компиляции (поведение во время выполнения кажется мне разумным). И не стесняйтесь использовать в ответ демо-версию godbolt :)
объяснение имеет смысл: либо все индексированы, либо все аргументы, но смешивание не допускается, если включены проверки во время выполнения.
@PennyDreudter Нет, это смешивание запрещено, если не включены проверки во время выполнения. См. ссылку на демонстрацию в моем предыдущем комментарии.
Несвязано: используйте
#include <print>
,#include <format>
иstd::println
, если у вас есть поддержка C++23.