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:

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Generic Programming (Templates) with C++": October 2024
  • "Embedded Programming with Modern C++": October 2024
  • "Clean Code: Best Practices for Modern C++": March 2025
  • Do you want to stay informed: Subscribe.

     

    • b: binary format
    • B: same as b, but the base prefix is 0B
    • d: decimal format
    • o: octal format
    • x: hexadecimal format
    • X: same as x, but the base prefix is 0X

    char and wchar_t:

    •  b, B, d, o, x, X: such as integers

    bool:

    • s: true or false
    • b, B, d, o, x, X: such as integers

    Floating-point:

    • e: exponential format
    • E: same as e, but the exponent is written with E
    • f, F: fixed point; precision is 6
    • g, G: precision 6, but the exponent is written with E

    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)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 176 5506 5086
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org

    Modernes C++ Mentoring,