Just in case you weren’t already aware, a part of the upcoming C++20 Standard is a text formatting library (based upon the popular, free, third-party {fmt} library). It looks like being a great addition to the Standard Library, providing ease-of-use, performance and type-safety.
Before we put the <iomanip>
and <cstdio>
C++ headers into the museum however, lets look at something which is also possible in Modern C++, using a printf()
-style format string to construct a std::string
. The prototype of this function is therefore:
std::string string_printf(const char *fmt,...);
To use the (optional) variadic arguments pack indicated by the ellipsis we need to use the functionality from the <cstdarg>
header, in the form of some clever macros: va_list
, va_start
and va_end
. Actually we need two va_list
s, so we use va_copy
as well.
The printf()
family functions which take a format string and a va_list
all begin with “v”. The code below uses vsnprintf()
(with nullptr
and zero length as arguments) for just one purpose, its return code (being the length of the output string, not including the null terminator byte). This is used on the std::string
‘s resize()
member function. We then call vsprintf()
with the writable (since C++17) data()
member of the string as the pointer value. Finally, a call to pop_back()
(a C++11 addition) removes the null terminator byte from the std::string
, and this is passed as the function’s return value. The complete function is shown below:
#include <cstdio>
#include <cstdarg>
#include <string>
inline std::string string_printf(const char *fmt,...) {
std::string s{};
va_list args, args2;
va_start(args, fmt);
va_copy(args2, args);
s.resize(vsnprintf(nullptr, 0, fmt, args2) + 1);
va_end(args2);
vsprintf(s.data(), fmt, args);
va_end(args);
s.pop_back();
return s;
}
The main performance hit with this approach is the need to call two printf()
-family functions in order to reserve exactly the right amount of buffer space. It is likely to be quicker than using C++ streams with manipulators, but maybe std::format
will be faster still, as well as being type-safe.
Resources
Download or browse the source code
[…] mentioned in a previous post, the popular C++ {fmt} library has been added to Modern C++ (in the form of the standard header […]
LikeLike