Member function seperti cout.width(8) bekerja, tetapi memutus alur penulisan: kita harus keluar dari rantai <<, mengatur lebar, lalu masuk lagi. Manipulator menyelesaikan masalah ini — ia adalah “nilai khusus” yang disisipkan langsung ke rantai << dan mengubah perilaku stream pada saat itu juga, sehingga satu pernyataan bisa mencakup pengaturan sekaligus data. Chapter ini mengajarkan manipulator yang paling sering dipakai: pengaturan kolom (setw, setfill, left, right), format angka (fixed, setprecision), basis bilangan (hex, dec, oct), penampilan bool (boolalpha), serta menimbang std::endl melawan '\n' biasa.

Manipulator: Pengaturan di Tengah Rantai #

Secara mekanis, manipulator adalah objek yang operator << perlakukan secara istimewa: alih-alih dicetak, ia memanggil fungsi pengaturan pada stream. Dua kelompoknya terpisah di dua header. Manipulator yang butuh argumen — std::setw(n), std::setprecision(n), std::setfill(c) — tinggal di <iomanip> dan wajib kita include. Manipulator tanpa argumen — std::left, std::right, std::fixed, std::hex, std::boolalpha — tinggal di <ios> yang sudah terbawa lewat <iostream>.

Mengenai masa berlaku, ada dua kelas manipulator yang perlu kita pisahkan sejak awal. setw adalah manipulator sekali pakai: ia hangus setelah satu output. Selebihnya bersifat menempel (sticky): fixed, setprecision, left, hex, dan kawan-kawannya tetap aktif sampai kita menggantinya — justru di sinilah sumber bug format yang paling sering muncul.

Tabel Rapi dengan setw, setfill, left, dan right #

Contoh berikut mencetak laporan stok tiga produk sebagai tabel yang sejajar sempurna — kasus klasik yang memakai hampir semua manipulator kolom:

cpp
#include <iomanip>
#include <iostream>
#include <string>

struct Produk {
    std::string nama;
    int stok;
    double harga;
};

int main() {
    Produk daftar[] = {
        {"Kopi Toraja", 12, 45000.0},
        {"Teh Hijau", 105, 18500.5},
        {"Gula Pasir", 7, 15500.0},
    };

    // Header tabel
    std::cout << std::left  << std::setw(14) << "Nama"
              << std::right << std::setw(6)  << "Stok"
              << std::setw(12) << "Harga" << '\n';
    std::cout << std::setfill('-') << std::setw(32) << "" << '\n';
    std::cout << std::setfill(' ');

    // Isi tabel
    std::cout << std::fixed << std::setprecision(2);
    for (const Produk& p : daftar) {
        std::cout << std::left  << std::setw(14) << p.nama
                  << std::right << std::setw(6)  << p.stok
                  << std::setw(12) << p.harga << '\n';
    }
    return 0;
}

Output yang Dihasilkan:

text
Nama            Stok       Harga
--------------------------------
Kopi Toraja       12    45000.00
Teh Hijau        105    18500.50
Gula Pasir         7    15500.00

Baris demi baris yang menentukan bentuk output:

  1. Baris 19-21 (header): std::left membuat kolom Nama rata kiri dalam lebar 14, sedangkan std::right meratakan kanan kolom Stok dan Harga — angka memang lazim rata kanan agar digitnya sejajar vertikal.
  2. Baris 22 (garis pemisah): trik yang sering dipakai — string kosong "" dengan setw(32) dan pengisi '-' mencetak 32 tanda hubung tanpa karakter lain.
  3. Baris 23 (setfill(' ')): pengisi dikembalikan ke spasi agar isi tabel tidak ikut bergaris; setfill menempel sampai diganti lagi.
  4. Baris 26 (fixed + setprecision(2)): fixed mengubah arti presisi menjadi “jumlah digit di belakang koma”, sehingga 45000.0 tampil 45000.00 — persis gaya laporan harga.
  5. Baris 28-30 (loop): setw(14), setw(6), dan setw(12) di-set ulang setiap kali karena sifatnya sekali pakai; tanpa pengulangan ini, hanya kolom pertama yang rapi.

Basis Bilangan dan boolalpha #

Manipulator berikutnya mengubah cara angka ditampilkan, bukan tata letaknya. std::hex, std::dec, dan std::oct memilih basis penulisan untuk int, sementara std::boolalpha dan std::noboolalpha menentukan apakah bool tampil sebagai true/false atau 1/0.

cpp
#include <iomanip>
#include <iostream>

int main() {
    int nilai = 255;

    std::cout << "dec : " << std::dec << nilai << '\n';  // basis 10
    std::cout << "hex : " << std::hex << nilai << '\n';  // basis 16
    std::cout << "oct : " << std::oct << nilai << '\n';  // basis 8

    std::cout << std::showbase;      // tampilkan awalan basis
    std::cout << "hex+ : " << std::hex << nilai << '\n'; // 0xff
    std::cout << std::noshowbase;

    std::cout << std::dec << "Kembali ke desimal: " << nilai << '\n';

    bool aktif = true;
    std::cout << "Bawaan : " << aktif << '\n';                      // 1
    std::cout << std::boolalpha << "Alpha  : " << aktif << '\n';    // true
    std::cout << std::noboolalpha << "Kembali: " << aktif << '\n';  // 1
    return 0;
}

Output yang Dihasilkan:

text
dec : 255
hex : ff
oct : 377
hex+ : 0xff
Kembali ke desimal: 255
Bawaan : 1
Alpha  : true
Kembali: 1

Tiga hal penting dari program ini: pertama, manipulator basis menempel — setelah std::hex, semua int berikutnya tercetak heksadesimal sampai kita menulis std::dec lagi (baris 14 memang sengaja menunjukkan pemulihannya). Kedua, std::showbase menambah awalan resmi 0x untuk heksadesimal dan 0 untuk oktal, membantu pembaca mengenali basisnya. Ketiga, boolalpha sangat berguna saat output program dibaca manusia, misalnya Sistem aktif: true terasa lebih alami daripada Sistem aktif: 1.

endl versus ‘\n’ #

Perbedaan std::endl dengan '\n' sering dianggap gaya penulisan, padahal ini soal teknis. Keduanya sama-sama menulis karakter newline, tetapi std::endl tambahan memaksa flush — buffer stream dikosongkan ke tujuan seketika. Tabel berikut meringkasnya:

'\n'std::endl
Menulis newlineYaYa
Memaksa flushTidakYa
Biaya di loop besarRinganBerat (satu flush per baris)
Cocok untukMayoritas kasusProgress saat proses panjang, log kritis, debug interaktif
cpp
// Dalam loop ribuan iterasi, versi kiri jauh lebih cepat:
std::cout << baris << '\n';        // dianjurkan
std::cout << baris << std::endl;   // flush di setiap baris

Sampai di sini kita bisa memformat output apa pun dengan rapi. Tapi output yang rapi menjadi percuma jika inputnya tidak valid — dan kegagalan cin membaca angka adalah jebakan klasik yang akan kita atasi dengan cin.clear() dan cin.ignore() pada Chapter berikutnya.

Referensi #