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:
#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:
Nama Stok Harga
--------------------------------
Kopi Toraja 12 45000.00
Teh Hijau 105 18500.50
Gula Pasir 7 15500.00Baris demi baris yang menentukan bentuk output:
- Baris 19-21 (header):
std::leftmembuat kolomNamarata kiri dalam lebar 14, sedangkanstd::rightmeratakan kanan kolomStokdanHarga— angka memang lazim rata kanan agar digitnya sejajar vertikal. - Baris 22 (garis pemisah): trik yang sering dipakai — string kosong
""dengansetw(32)dan pengisi'-'mencetak 32 tanda hubung tanpa karakter lain. - Baris 23 (
setfill(' ')): pengisi dikembalikan ke spasi agar isi tabel tidak ikut bergaris;setfillmenempel sampai diganti lagi. - Baris 26 (
fixed+setprecision(2)):fixedmengubah arti presisi menjadi “jumlah digit di belakang koma”, sehingga45000.0tampil45000.00— persis gaya laporan harga. - Baris 28-30 (loop):
setw(14),setw(6), dansetw(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.
#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:
dec : 255
hex : ff
oct : 377
hex+ : 0xff
Kembali ke desimal: 255
Bawaan : 1
Alpha : true
Kembali: 1Tiga 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 newline | Ya | Ya |
| Memaksa flush | Tidak | Ya |
| Biaya di loop besar | Ringan | Berat (satu flush per baris) |
| Cocok untuk | Mayoritas kasus | Progress saat proses panjang, log kritis, debug interaktif |
// 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.