Search code examples
c++c++20fmt

How to correctly use named args in C++ Fmt library


I have the following bit of code, that uses a runtime determined width:

#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;
}

I expect it to output the lines as follows prefixing each line with a line number that is right-aligned and padded with "0"

000 line 1 - xxxxxxxx
001 line 2 - xxxxxxxx
002 line 3 - xxxxxxxx
003 line 4 - xxxxxxxx

However when I run it, I get the following runtime exception:

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

I'm not sure where I'm going wrong here, I'm using the syntax detailed in the Argument-Determined Width section from here:

https://hackingcpp.com/cpp/libs/fmt.html


Godbolt link: https://godbolt.org/z/fzv66KGe1


Solution

  • I can't find it documented anywhere but it looks like you can't mix automatic arguments with named or indexed arguments, you can do either:

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

    Or

    "{:0{}} {}"
    

    std::format does document this restriction:

    specifies the index of the argument in args whose value is to be used for formatting; if it is omitted, the arguments are used in order.

    The arg-id s in a format string must all be present or all be omitted. Mixing manual and automatic indexing is an error.