C++ IO and Formatting


  • Description: A note on C++ I/O streams, formatting manipulators, std::bind with placeholders, and modern formatting (std::format, std::print)
  • My Notion Note ID: K2A-B1-20
  • Created: 2018-12-27
  • Updated: 2026-02-28
  • License: Reuse is very welcome. Please credit Yu Zhang and link back to the original on yuzhang.io

Table of Contents


1. std::ios_base::openmode

  • File-open flags, combinable:
Flag Meaning
std::ios_base::in Open for reading
std::ios_base::out Open for writing
std::ios_base::app Seek to end of stream before each write (append)
std::ios_base::ate Seek to end of stream immediately after opening
std::ios_base::trunc Discard existing contents when opening
std::ios_base::binary Open in binary mode (no text translation)
#include <fstream>

// Open for reading and writing in binary mode
std::fstream file("data.bin",
    std::ios_base::in | std::ios_base::out | std::ios_base::binary);

// Open for appending (does not truncate existing content)
std::ofstream log("app.log", std::ios_base::app);

// Open for writing, truncating existing content (default for ofstream)
std::ofstream out("output.txt", std::ios_base::out | std::ios_base::trunc);

2. Stream Formatting: std::setw and std::setfill

  • <iomanip> — manipulators for output formatting.
  • setw = minimum field width; setfill = padding character.
#include <iostream>
#include <iomanip>

int main() {
    int value = 42;

    // Pad with zeros to a width of 9 characters
    std::cout << std::setw(9) << std::setfill('0') << value << std::endl;
    // Output: 000000042

    // Right-align with spaces (default)
    std::cout << std::setw(9) << std::setfill(' ') << value << std::endl;
    // Output:        42

    // Left-align
    std::cout << std::left << std::setw(9) << std::setfill('.') << value << std::endl;
    // Output: 42.......

    return 0;
}
  • Note: setw resets after each insertion. setfill persists until changed.

Other common <iomanip> manipulators:

  1. setprecision(n) — digits for FP output. Combine with fixed / scientific.
  2. hex, oct, dec — integer base for in/out.
  3. boolalpha / noboolalpha — print booleans as true/false vs 1/0.
  4. showbase — prefix 0x / 0 on hex / octal.

3. std::bind and std::placeholders

  • std::bind — new callable by fixing some args of an existing callable; rest are placeholders for future args.

3.1 std::placeholders

  • Placeholders _1, _2, _3, ... mark positions for future args. _1 = first arg passed to bound fn. Numbering starts at _1.

3.2 std::bind

  • Produces a forwarding call wrapper. Calling it invokes original with bound args substituted.
#include <functional>
#include <iostream>

int sum(int a, int b) {
    return a + b;
}

int main() {
    using namespace std::placeholders;

    // Bind the second argument to 3; _1 is the first argument passed to add_3
    auto add_3 = std::bind(sum, _1, 3);
    std::cout << add_3(4) << std::endl;  // sum(4, 3) = 7

    // Swap argument order
    auto swapped = std::bind(sum, _2, _1);
    std::cout << swapped(10, 20) << std::endl;  // sum(20, 10) = 30

    return 0;
}

3.3 Modern Alternative: Lambdas

  • Lambdas usually clearer + more flexible than bind:
// Equivalent to std::bind(sum, _1, 3)
auto add_3 = [](int x) { return sum(x, 3); };

Why prefer lambdas:

  1. Easier to read.
  2. Predictable with overloads (no ambiguity in overload resolution).
  3. Better optimization — compiler inlines through them; bind often type-erased.
  4. Support generic captures ([](auto x) { ... }) and capture-by-move ([p = std::move(ptr)] { ... }) — bind cannot.

4. std::format and std::print (C++20/23)

  • std::format (C++20, <format>) + std::print (C++23, <print>) — modern alternatives to << and printf.
#include <format>
#include <print>          // C++23

std::string s = std::format("Hello, {}!", "world");        // "Hello, world!"
std::print("count = {}\n", 42);                            // C++23: print to stdout
std::println("widget at ({}, {})", 1, 2);                  // adds a newline
std::format_to(buf, "pid {}", pid);                         // write to an iterator
printf << (iostream) std::format
Type-safe No (format-string mismatch is runtime UB) Yes Yes
Custom types Manual Overload << Specialize std::formatter<T>
Speed Fast Slow Fast
Positional args No No Yes ({0}, {1})
Compile-time format check No N/A Yes (C++20)
Locale-independent Yes Mixed Yes (default)