The Formatting Library in C++20: The Format String (2)
In my last post, “The Formatting Library in C++20: The Format String“, I presented a few of the format specifications of the format string. Today, I finish my job.
In today’s post, I will write about the width, precision, and type of the format specification. If you want to know more about the argument id, fill characters, alignment, signess, and the alternative form, read my previous post: “The Formatting Library in C++20: The Format String“.
Width and Precision
You can specify the width and the precision of your argument. The width specifier can be applied to numbers, and the precision to floating-point numbers and strings. For floating-point types, the precision specifies the formatting precision; for strings, the precision specifies how many characters are used and, ultimately, trimming the string. It does not affect a string if the precision is greater than the length of the string.
- width: you can use either a positive decimal number or a replacement field (
{}
or{n}
). When given,n
specifies the minimum width. - precision: you can use a period (
.)
followed by a non-negative decimal number or a replacement field.
A few examples should help you grasp the basics:
// formatWidthPrecision.cpp #include <format> #include <iostream> #include <string> int main() { int i = 123456789; double d = 123.456789; std::cout << "---" << std::format("{}", i) << "---\n"; std::cout << "---" << std::format("{:15}", i) << "---\n"; // (w = 15) std::cout << "---" << std::format("{:}", i) << "---\n"; // (w = 15) // (1) std::cout << '\n'; std::cout << "---" << std::format("{}", d) << "---\n"; std::cout << "---" << std::format("{:15}", d) << "---\n"; // (w = 15) std::cout << "---" << std::format("{:}", d) << "---\n"; // (w = 15) std::cout << '\n'; std::string s= "Only a test"; std::cout << "---" << std::format("{:10.50}", d) << "---\n"; // (w = 10, p = 50) // (2) std::cout << "---" << std::format("{:{}.{}}", d, 10, 50) << "---\n"; // (w = 10, // (3) // p = 50) std::cout << "---" << std::format("{:10.5}", d) << "---\n"; // (w = 10, p = 5) std::cout << "---" << std::format("{:{}.{}}", d, 10, 5) << "---\n"; // (w = 10, // p = 5) std::cout << '\n'; std::cout << "---" << std::format("{:.500}", s) << "---\n"; // (p = 500) // (4) std::cout << "---" << std::format("{:.{}}", s, 500) << "---\n"; // (p = 500) // (5) std::cout << "---" << std::format("{:.5}", s) << "---\n"; // (p = 5) }
The w
character in the source code stands for the width; similarly, the p
character for the precision. I have a few interesting observations about the program. No extra spaces are added when you specify the width with a replacement field (line 1). When you specify a precision higher than the length of the displayed double
(lines 2 and 3), the length of the displayed value reflects the precision. This observation does not hold for a string (lines 4 and 5).
Additionally, you can also parametrize the width and the precision.
// formatWidthPrecisionParametrized.cpp #include <format> #include <iostream> int main() { std::cout << '\n'; double doub = 123.456789; std::cout << std::format("{:}\n", doub); // (1) std::cout << '\n'; for (auto precision: {3, 5, 7, 9}) { std::cout << std::format("{:.{}}\n", doub, precision); // (2) } std::cout << '\n'; int width = 10; for (auto precision: {3, 5, 7, 9}) { std::cout << std::format("{:{}.{}}\n", doub, width, precision); // (3) } std::cout << '\n'; }
The program formatWidthPrecisionParametrized.cpp
displays the double doub
in various ways. Line (1) applies the default. Line (2) varies precision
from 3 to 9. The last argument of the format string goes into the inner {}
of the format specifier {:.{}}
. Finally, line (3) sets the width of the displayed doubles to 10.
Type
In general, the compiler deduces the type of the value used. But sometimes, you want to specify the type. These are the most important type specifications:
Strings: s
Integers:
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
b
: binary formatB
: same asb
, but the base prefix is0B
d
: decimal formato
: octal formatx
: hexadecimal formatX
: same asx
, but the base prefix is0X
char
and wchar_t
:
-
b, B, d, o, x, X
: such as integers
bool
:
- s:
true
orfalse
b, B, d, o, x, X
: such as integers
Floating-point:
e
: exponential formatE
: same ase
, but the exponent is written withE
f, F
: fixed point; precision is 6g, G
: precision 6, but the exponent is written withE
Pointer:
p
: hexadecimal notation of its address
Only void
, const void
, and std::nullptr_t
pointer types are valid. If you want to display the address of an arbitrary pointer, you must cast it to (const) void*
.
double d = 123.456789; std::format("{}", &d); // ERROR std::format("{}", static_cast<void*>(&d)); // okay std::format("{}", static_cast<const void*>(&d)); // okay std::format("{}", nullptr); // okay
The type specifiers allow you to display an int
in a different number system.
// formatType.cpp #include <format> #include <iostream> int main() { int num{2020}; std::cout << "default: " << std::format("{:}", num) << '\n'; std::cout << "decimal: " << std::format("{:d}", num) << '\n'; std::cout << "binary: " << std::format("{:b}", num) << '\n'; std::cout << "octal: " << std::format("{:o}", num) << '\n'; std::cout << "hexadecimal: " << std::format("{:x}", num) << '\n'; }
What’s Next?
So far, I’ve formatted basic types and strings. Additionally, you can format user-defined types. This will be the topic of my next post.
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, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, 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, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | |
My special thanks to PVS-Studio | |
My special thanks to Tipi.build | |
My special thanks to Take Up Code | |
My special thanks to SHAVEDYAKS |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org
Modernes C++ Mentoring,