std::format#
Note
We will look at the C++20 way to format output. An alternate way to set precision and how wide an output field is can be found in the iomanip library
Important
You need to use C++20 for this method. This means using GCC >= 13,
and adding the -std=c++20 flag when compiling.
std::format takes
a string as the first argument with {} embedded as placeholders
and then inserts the remaining arguments into the string, in order, in
the {}.
We’ll look at its basic usage.
Basic output#
Here’s a simple example:
#include <iostream>
#include <format>
#include <string>
int main() {
int x{10};
double y{1.23e-4};
std::string a{"test"};
std::string formatted = std::format("x = {}; y = {}; a = {}\n", x, y, a);
std::cout << formatted;
}
When run, this outputs x = 10; y = 0.000123; a = test with a new line (since
we added the \n;
Each variable / object we specify as an argument after the first
argument is inserted in order into the {} in the format string.
Note
You need to include the <format> header to use std::format.
Tip
We don’t need to make an intermediate string, we could just send the
output of std::format to the output stream, std::cout directly
like:
std::cout << std::format("x = {}; y = {}; a = {}\n", x, y, a);
If we include more arguments after the format string than there are {}, the
extra arguments are just ignored:
#include <iostream>
#include <format>
#include <string>
int main() {
int x{10};
double y{1.23e-4};
double z{-10.5};
std::string a{"test"};
std::cout << std::format("x = {}; y = {}; a = {}\n", x, y, a, z);
}
If we don’t provide enough arguments, then the code will not compile.
Formatting#
Within the {} we can specify the formatting using format specifiers.
Note
These specifiers are the same as used in the Python programming language. A detailed overview is given in the python docs for the format specification mini-language
The basic form is {:specifier}, where the specifier has fields giving:
Filling and alignment
sign, 0 padding
width
precision
type
We;ll look at the basic cases that we usually care about—mainly specifying the width of the output, the precision, and the type.
Here’s an example:
#include <iostream>
#include <format>
#include <string>
int main() {
int x{10};
double y{1.23e-6};
double z{10.25};
std::string a{"test"};
std::cout << std::format("(x = {:03d}; y = {:8.3g}; z = {:4.1f} a = {:10})\n", x, y, z, a);
}
this gives:
(x = 010; y = 1.23e-06; z = 10.2 a = test )
Let’s see what these do:
for the
int x{10}, we use the specifier03d.This uses 3 characters for the width of the field, puts
0s in any empty field, and thedspecifies that it is an integer.for the
double y{1.23e-6}, we use the specifier8.3g.This says to use 8 characters for the width with 3 digits of precision after the decimal, and the
gasks it to use scientific notation for large exponents and fixed formatting for small exponents.for the
double z{10.25}, we use the specifier4.1f.This says to use 4 characters for the width with 1 digit of precision after the decimal, and the
frequires it to use fixed-format (never switch to scientific notation).for the
std::string a{"test"}, we use the specifier10.This says to use 10 characters for the width. Since our string is only 4 characters long, we see that it adds spaces to the end.
Tip
Specifying the width is a great way to output data in columns, which will make it easy to plot. We’ll see this later.
std::print#
In C++23, things become even simpler, with the addition of std::print and std::println.
For example, we can do:
#include <print>
int main() {
std::println("Hello, World");
}
and compile this as:
g++ -std=c++23 -o println println.cpp
The difference between std::print and std::println is that std::println adds
a newline to the end.
Note
This requires GCC >= 14