Peter Gottschling presented in his last post "std::format in C++20" the basics of the new formatting library in C++20. In today's post, Peter writes about the formatting of user-defined types.

Our first example of template specialization is customizing the new format library introduced to support user types.
For example, we choose the dmc::vector
(dmc
is the namespace from the book "Discovering Modern C++" by the author) class for which we like to specify the formatting of the single values. In addition, we want to replace the enclosing brackets with curly braces when the format string contains the letter 'c'
. To this end, we have to specialize the class std::formatter
(or fmt::formatter
for the prototype library fmt
). Our specialization shall contain the methods parse
and format
.
Let's start with the former:
template <typename Value>
struct formatter<dmc::vector<Value>>
{
constexpr auto parse(format_parse_context& ctx)
{
value_format= "{:";
for (auto it= begin(ctx); it != end(ctx); ++it) {
char c= *it;
if (c == 'c')
curly= true;
else
value_format+= c;
if (c == '}')
return it;
}
return end(ctx);
}
// ...
bool curly{false};
std::string value_format;
};
As an argument, the parse context is given whose begin
iterator points to the first character of the format specification, i.e.~the first character after the colon and, in its absence, the first character after the opening brace. We copy the format specification almost identically to our local value_format,
only our unique character 'c'
is skipped. For simplicity, we assume that the format doesn't contain any opening or closing brace, so the next closing brace terminates our format string. Finally, we return the iterator pointing to the closing brace or the end iterator.
With this information, we can output our vector
in the method format
:
template <typename Value>
struct formatter<dmc::vector<Value>>
{
template <typename FormatContext>
auto format(const dmc::vector<Value>& v, FormatContext& ctx)
{
auto&& out= ctx.out();
format_to(out, curly ? "{{" : "[");
if (v.size() > 0)
format_to(out, value_format, v[0]);
for (int i= 1; i < v.size(); ++i)
format_to(out, ", " + value_format, v[i]);
return format_to(out, curly ? "}}" : "]");
}
// ...
};
First, we take a reference to the output buffer. Then we write the opening brace or bracket to it. Since braces have a special meaning in the format
library, we need an escape sequence of double braces. The remaining output is equivalent to the ostream
output. Finally, we return the output buffer.
Now we can try various formats:
dmc::vector<double> v{1.394, 1e9, 1.0/3.0, 1e-20};
print("v with empty format = {:}.\n", v);
print("v with f = {:f}.\n", v);
print("v curly with f = {:fc}.\n", v);
print("v width 9, 4 digits = {:9.4f}.\n", v);
print("v scient. = {:ec}.\n", v);
and see the outputs:
v with empty format = [1.394, 1000000000.0, 0.3333333333333333, 1e-20].
v with f = [1.394000, 1000000000.000000, 0.333333, 0.000000].
v curly with f = {1.394000, 1000000000.000000, 0.333333, 0.000000}.
v width 9, 4 digits = [ 1.3940, 1000000000.0000, 0.3333, 0.0000].
v scient. = {1.394000e+00, 1.000000e+09, 3.333333e-01, 1.000000e-20}.
Altogether, since the new formatting is:
- Compact: demonstrated in the examples above
- Adaptable: to various output orders
- Type-safe: an exception is thrown when an argument doesn't match
- Extensible: can be extended to user-defined types
For those reasons, it is superior to the preceding techniques, and we strongly advise using it as soon as sufficient compiler support is available.
Thanks once more to Peter Gottschling for providing a compact introduction to std::format
. Let me add a few words to complete his introduction to the formatting library.
Modernes C++ Mentoring
Be part of my mentoring programs:
Do you want to stay informed about my mentoring programs: Subscribe via E-Mail.
Try It Out
As Peter mentioned, the GitHub-hosted fmt
library is a prototype for the new formatting library in C++20. The project's front page includes a few straightforward examples and performance numbers. These examples include a direct link to the compiler explorer for executing the example.
Thanks to the new formatting library, you can display time durations of the chrono
library:
#include <fmt/chrono.h>
int main() {
using namespace std::literals::chrono_literals;
fmt::print("Default format: {} {}\n", 42s, 100ms);
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}
Executing the program on the compiler explorer gives you the following output:

Porting to C++20
Porting the previous program from fmt
the C++20 format library is a piece of cake. You have to use the C++ standard header chrono
and iostream
. Additionally, replace the call fmt::print
with the function std::format
and push the result to std::cout
. std::format
returns a string according to the given format string and an optional local.
// formatChrono.cpp
#include <chrono>
#include <iostream>
int main() {
using namespace std::literals::chrono_literals;
std::cout << std::format("Default format: {} {}\n", 42s, 100ms) << "\n";
std::cout << std::format("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s) << "\n";
}
What's next?
In my next post, I will continue with the convenience functions. With C++20, you can calculate the midpoint of two values, check if a std::string
start or ends with a substring, and create callables with std::bind_front
.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, and Rob North.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.
My special thanks to Embarcadero 
My special thanks to PVS-Studio 
My special thanks to Tipi.build 
My special thanks to Take Up Code 
Seminars
I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
Bookable (Online)
German
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ - The Core Language
- C++ - The Standard Library
- C++ - Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
New
- Clean Code with Modern C++
- C++20
Contact Me
- Phone: +49 7472 917441
- Mobil:: +49 176 5506 5086
- Mail: This email address is being protected from spambots. You need JavaScript enabled to view it.
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++,

Comments
RSS feed for comments to this post