Как правильно использовать именованные аргументы в библиотеке C++ Fmt

У меня есть следующий фрагмент кода, который использует ширину, определенную во время выполнения:

#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

Несвязано: используйте #include <print>, #include <format> и std::println, если у вас есть поддержка C++23.

user12002570 01.09.2024 07:15

@user12002570 user12002570 Невозможно использовать функции формата std, поскольку кодовая база — C++20. Кроме того, я не думаю, что то, что доступно в C++23, позволяет использовать спецификаторы формата во время выполнения.

Penny Dreudter 01.09.2024 07:18

Вам следует добавить тег c++20.

user12002570 01.09.2024 07:20

Примечание: почему вы не ссылаетесь на собственную документацию fmt? (fmt.dev/11.0/api).

Pepijn Kramer 01.09.2024 07:31

@PennyDreudter C++20/23 поддерживает аргументы во время выполнения. Он просто не поддерживает именованные аргументы, вам нужны аргументы на основе индекса (позиционные).

Red.Wave 01.09.2024 08:05
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
158
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нигде не могу найти это задокументировано, но похоже, что вы не можете смешивать автоматические аргументы с именованными или индексированными аргументами, вы можете сделать следующее:

"{0:0{width}} {2}"

Или

"{:0{}} {}"

std::format документирует это ограничение:

указывает индекс аргумента в args, значение которого будет использоваться для форматирования; если он опущен, аргументы используются по порядку.

Идентификаторы аргументов в строке формата должны присутствовать все или быть опущены. Смешение ручной и автоматической индексации является ошибкой.

Вам следует добавить живую демо-версию (godbolt), по крайней мере, поскольку у нас нет официального источника для этого, поэтому, если в будущем что-то изменится, у нас будет ссылка на демо-версию, которая показывает эту работу.

user12002570 01.09.2024 08:43

Смешение ручной и автоматической индексации является ошибкой только для версии времени компиляции. Для версии времени выполнения, как и в вопросе ОП, их можно смешивать с тем ограничением, что вы не можете переключаться с ручного на автоматический. Итак, в случае OP {:0{width}} {2}", i, fmt::arg("width",width), line); работает нормально (где нужно указать только 2, поскольку ему предшествует ручной индекс с width). godbolt.org/z/cWrP7vfKj Не знаю, почему существует несоответствие между версиями времени выполнения и компиляции (поведение во время выполнения кажется мне разумным). И не стесняйтесь использовать в ответ демо-версию godbolt :)

cigien 01.09.2024 09:00

объяснение имеет смысл: либо все индексированы, либо все аргументы, но смешивание не допускается, если включены проверки во время выполнения.

Penny Dreudter 01.09.2024 09:53

@PennyDreudter Нет, это смешивание запрещено, если не включены проверки во время выполнения. См. ссылку на демонстрацию в моем предыдущем комментарии.

cigien 01.09.2024 11:51

Другие вопросы по теме