If you like this content, or if it helps you, leave a ⭐!
std::format is a text formatting library introduced in C++20, offering a safe and extensible alternative to the printf family of functions. It aims to complement the existing C++ I/O streams library by reusing some of its infrastructure, such as overloaded insertion operators for user-defined types.
Prior to C++20, formatting text in C++ was often error-prone and inconsistent, relying on functions like printf or stream-based formatting. std::format was introduced to provide a safer, more consistent, and modern approach to text formatting.
Unlike printf, std::format offers:
- ✅ Type safety
- ✅ Compile-time format string checking
- ✅ A clean, modern syntax
- ✅ Integration with user-defined types through overloaded insertion operators
std::string result = std::format(format_string, args...);Description: Formats the given arguments (args...) according to the format_string and returns the result as a std::string.
auto it = std::format_to(output_iterator, format_string, args...);Description: Formats the arguments just like std::format, but writes the result directly to an output buffer using an output iterator.
cppreference.com: std::format_to
auto result = std::format_to_n(output_iterator, n, format_string, args...);Description: Like format_to, but limits the output to a maximum of n characters. Returns a pair consisting of an output iterator pointing past the last written character and the number of characters that would have been written.
cppreference.com: std::format_to_n
size_t size = std::formatted_size(format_string, args...);Description: Returns the number of characters that would be produced by std::format (without actually formatting or allocating memory). Useful for pre-allocating buffers.
cppreference.com: std::format_size
#include <format>| compiler support | Text Formatting (C++20) | status |
|---|---|---|
| Visual Studio | VS 2019 16.10 / cl 19.29 | completed |
| GCC | 13.1 | completed |
| clang | 14 | completed |
Source: cppreference
#include <cstdio> // C library for Input/Output operationsconst int answer { 42 };
printf( "The answer is %d ", answer );const int answer { 42 };
std::cout << "The answer is " << answer << "\n";const int answer { 42 };
std::cout << boost::format( "The answer is %") % answer;const int answer { 42 };
ff::fmtll( std::cout, "The answer is {0}", answer );www.fastformat.org or github.com/synesissoftware/FastFormat
const int answer { 42 };
std::cout << std::format( "The answer is {}", answer );The {} indicates a replacement field like % in printf.
std::cout << std::format( "The answer is {}", 42 );Writes the following output:
The answer is 42std::cout << std::format( "I'd rather be {1} than {0}", "right", "happy" );std::cout << std::format( "The answer is {{ }}", 42 );Placeholder can contains a format specifiers. It starts with a colon: {[index]:[format specifiers]}
[[fill]align][sign][#][0][width][.precision][type]
minimum desired field width
std::cout << std::format( "{:5}", 42 );std::cout << std::format( "{:{}}", 42, 5 );Specifies optional characters and aligment
< left
> right
^ center
std::cout << std::format( "{:<20}", "left");std::cout << std::format( "{:>20}", "right");std::cout << std::format( "{:^20}", "centered");std::cout << std::format( "{:-^20}", "centered");- sign only for negative numbers (default)
+ sign for negative and positive numbers
scape display minus sign for negative numbers, a space for positive numbers
std::cout << std::format( "{:<5}", 42 );std::cout << std::format( "{:<+5}", 42 );std::cout << std::format( "{:< 5}", 42 );std::cout << std::format( "{:< 5}", -42 );enabled alternative formatting rules
integral types
- Hexadecimal format: inserts 0x or 0X at font
- Binray format: inserts 0b or 0B at font
- Octal format: inserts 0
floating-points types
- always show decimal separator, even without following digits
std::cout << std::format( "{:15d}", 42 );std::cout << std::format( "{:15b}", 42 );std::cout << std::format( "{:#15b}", 42 );std::cout << std::format( "{:15X}", 42 );std::cout << std::format( "{:#15X}", 42 );only for floating-points types and strings types
const double pi { 3.1415 };
const int precision { 2 };
const int width { 15 };std::cout << std::format( "{:15.2f}", pi );std::cout << std::format( "{:15.{}f}", pi, precision );std::cout << std::format( "{:{}.{}f}", pi, width, precision );std::cout << std::format( "{0:{1}.{2}f}", pi, width, precision );std::locale is supported in std::format
Note: Use
:Lto enable locale specific formatting for an argument.
#include <locale>std::cout << std::format( locale( "en_US.UTF-8" ), "{:L}", 1024 );std::cout << std::format( locale( "zh_CN.UTF-8" ), "{:L}", 1024 );std::cout << std::format( locale( "de_DE.UTF-8" ), "{:L}", 1024 );#include <chrono>std::cout << std::format( "{:%d.%m.%Y}.", std::chrono::system_clock::now() ) << "\n";void print_happy_birthday( const std::string_view& name, const std::chrono::year_month_day& birthday )
{
std::cout << std::format( "{0}'s birthday is {1:%Y-%m-%d}.", name, birthday ) << "\n";
}using namespace std::chrono;
year_month_day birthday { 1976y / February / 1 };
std::string name { "Max Mustermann" };
print_happy_birthday( name , birthday );#include <complex>std::complex<double> c { 4.0, 8.0 };std::cout << std::format( "{}", c );Seperate parsing and formatting in extension API
Need to provide a specialization of std::formater<> and imlpement
- formatter<>::parse()
- formatter<>::format()
#include <format>
#include <iostream>
struct Point {
int x, y;
};
template <>
struct std::formatter<Point> {
constexpr auto parse( format_parse_context& context ) {
return context.begin();
}
template <typename FormatContext>
auto format( const Point& point, FormatContext& context ) {
return std::format_to( context.out(), "({}, {})", point.x, point.y );
}
};
int main() {
Point point{3, 7};
// Format to string
std::string formatted_point = std::format( "The point is: {}", point );
std::cout << formatted_point << '\n';
// Direct output using std::format_to and std::back_inserter
std::string buffer;
std::format_to( std::back_inserter( buffer ), "Formatted directly: {}\n", point );
std::cout << buffer;
return 0;
}class Person {
public:
Person() = delete;
Person( unsigned long long id, const std::string& firstName, const std::string& lastName ) noexcept
: _id( id ), _firstName( firstName ), _lastName( lastName ) {}
auto getId() const noexcept -> unsigned long long {
return _id;
}
auto getFirstName() const noexcept -> const std::string& {
return _firstName;
}
auto getLastName() const noexcept -> const std::string& {
return _lastName;
}
private:
unsigned long long _id;
std::string _firstName;
std::string _lastName;
};
template<>
class std::formatter<Person> {
public:
constexpr auto parse( auto& context ) {
}
auto format( const Person& person, auto& context ) {
}
};#include <format>
#include <iostream>
#include <string_view>
enum class Direction { North, East, South, West };
std::string_view to_string( Direction direction ) {
switch (direction) {
using enum Direction;
case North: return "north";
case East: return "east";
case South: return "south";
case West: return "west";
default: return "unknown";
}
}
template<>
struct std::formatter<Direction> : std::formatter<std::string_view> {
auto format( Direction direction, auto& context ) const {
return std::formatter<std::string_view>::format( to_string( direction ), context );
}
};
int main() {
Direction direction = Direction::East;
std::cout << std::format( "Direction: {}", direction ) << '\n';
}