There's a section on "why not printf" which is Standard C, but I can't find any section on "why not std::format"[1] which is Standard C++ since C++20 and works on all major compilers today in 2025.
They do mention "std::print"[2] from C++23 (which uses std::format) and compile times, but, they don't touch on "std::format" at all.
Is it in major compilers yet? Last I checked for MSVC it was behind a "latest" compiler flag (not C++20). I've been vendoring the fmt library for awhile now.
The subtext is a resource constrained system where std::format is considered too heavyweight. In that scenario, explicit non-automatic memory management is a benefit. It could still leverage std::string_view and be agnostic on the topic.
If you're willing to use one measly little macro - solely to smuggle the format string in a constexpr manner - instead of insisting on using templates everywhere, you can use a printf wrapper with essentially 0 compile-time overhead. And the only runtime overhead is if you have to copy a `string_view` back into a `string` to add the `NUL`-terminator.
You do still need templates for the arguments (unless you're willing to resort to nasty preprocessor hackery, which would be needed if doing this in C - hmm, are the lifetime-of-temporary rules different too?), but it's pretty easy to just do:
where `to_owning_primitive` is the ADL'ed function you implement for every type you want to print, and `to_borrowed_primitive` probably only needs to be implemented for each string type (though I did find it also useful for wrapped integers of unknown size/rank, such as `time_t`).
Nice. I think most people have tried doing something like this in C++ at some point.
One issue that I had is that printing floating-point values really needs the ability for the user to specify the precision and format. It's actually absurd that `std::to_string(double)` does not allow this.
Also, I believe `std::to_chars(double)` uses a fast algorithm and allows writing directly into a buffer.
Yes, true. But the probability of finding new CVEs from any 65 lines of non-obfuscated code diminishes rapidly. In many situations I'd rather use a short minimal fresh lib that I can review as if it was mine than a mature but overly feature-loaded one that may still have any number of pending gotchas in dark corners.
I must admit I was very much against the practice of NIH syndrome, but if it's that short I would prefer to write my own version instead of adding a dependency.
In this day and age who knows when a dependency is hijacked :(
At 65 lines, if the license is right, you can just copy it like you would with a StackOverflow answer. In these situations I leave a comment on top saying where the code came from so it can be revisited later.
There's a section on "why not printf" which is Standard C, but I can't find any section on "why not std::format"[1] which is Standard C++ since C++20 and works on all major compilers today in 2025.
They do mention "std::print"[2] from C++23 (which uses std::format) and compile times, but, they don't touch on "std::format" at all.
See:
[1] https://en.cppreference.com/w/cpp/utility/format/format.html
[2] https://en.cppreference.com/w/cpp/io/print.html
Is it in major compilers yet? Last I checked for MSVC it was behind a "latest" compiler flag (not C++20). I've been vendoring the fmt library for awhile now.
Clearly yes. BTW, I don't see a benefit to use a non-owning String_Buffer over std::string (or std::string_view) in this context.
The subtext is a resource constrained system where std::format is considered too heavyweight. In that scenario, explicit non-automatic memory management is a benefit. It could still leverage std::string_view and be agnostic on the topic.
I prefer https://github.com/rokudev/rostd/blob/main/doc/printx.adoc, but it does increase compile times (which OP was trying to avoid).
If you're willing to use one measly little macro - solely to smuggle the format string in a constexpr manner - instead of insisting on using templates everywhere, you can use a printf wrapper with essentially 0 compile-time overhead. And the only runtime overhead is if you have to copy a `string_view` back into a `string` to add the `NUL`-terminator.
You do still need templates for the arguments (unless you're willing to resort to nasty preprocessor hackery, which would be needed if doing this in C - hmm, are the lifetime-of-temporary rules different too?), but it's pretty easy to just do:
where `to_owning_primitive` is the ADL'ed function you implement for every type you want to print, and `to_borrowed_primitive` probably only needs to be implemented for each string type (though I did find it also useful for wrapped integers of unknown size/rank, such as `time_t`).Love the method name uhm bool next_hole
I much prefer string interpolation like
$"i={i}"
Nice. I think most people have tried doing something like this in C++ at some point.
One issue that I had is that printing floating-point values really needs the ability for the user to specify the precision and format. It's actually absurd that `std::to_string(double)` does not allow this.
Also, I believe `std::to_chars(double)` uses a fast algorithm and allows writing directly into a buffer.
How many CVEs?
Yes, true. But the probability of finding new CVEs from any 65 lines of non-obfuscated code diminishes rapidly. In many situations I'd rather use a short minimal fresh lib that I can review as if it was mine than a mature but overly feature-loaded one that may still have any number of pending gotchas in dark corners.
I must admit I was very much against the practice of NIH syndrome, but if it's that short I would prefer to write my own version instead of adding a dependency.
In this day and age who knows when a dependency is hijacked :(
At 65 lines, if the license is right, you can just copy it like you would with a StackOverflow answer. In these situations I leave a comment on top saying where the code came from so it can be revisited later.