Chapter Structured Bindings di section Struktur dan Tipe Data Komposit sudah memperkenalkan dasarnya: satu pernyataan C++17 membongkar isi objek menjadi beberapa nama — auto [kode, pesan] = hasil; — tanpa akses .first/.second yang menggangu pembacaan. Chapter ini memperdalam tiga hal yang menjadi penentu kenyamanan sehari-hari. Pertama, kita pastikan mekanismenya: nama-nama hasil binding bukan variabel baru, melainkan nama alternatif untuk bagian dalam objek, dan konsekuensinya mengikuti aturan deduksi yang sudah kita pegang dari chapter auto dan Type Deduction. Kedua, kita bandingkan tiga bentuk modifier — auto, auto&, const auto& — dengan bukti eksekusi siapa yang menyalin dan siapa yang mengalias. Ketiga, kita bedah use case yang paling sering muncul di kode nyata: iterasi std::map dengan nama bermakna alih-alih entry.first dan entry.second.

Empat Jenis Objek yang Bisa Dibongkar #

Structured binding bekerja pada empat kategori: struct/aggregate, std::pair, std::tuple, dan array (termasuk C-array). Di belakang layar compiler memperluasnya kira-kira seperti ini:

cpp Perluasan konseptual satu binding
auto [kode, pesan] = hasil;
// kurang lebih menjadi:
auto e = hasil;              // objek perantara
auto& kode  = e.first;       // nama alternatif ke bagian dalam
auto& pesan = e.second;

Objek perantara e adalah kuncinya: begitu ia dibuat dari ekspresi, umurnya diperpanjang sampai akhir scope binding — jadi auto [a, b] = fungsiYangMengembalikanPair(); aman meski sumbernya temporary. Perluasan ini juga menjelaskan dua batasan: jumlah nama harus persis sama dengan jumlah elemen (tidak ada “sisa”), dan semua nama wajib dideklarasikan sekaligus dalam satu baris. Untuk struct, urutan mengikuti urutan deklarasi member — makanya binding paling enak dipakai pada struct kecil yang membernya jelas nama dan maknanya.

Program Pendalaman #

cpp
// bindings.cpp — structured bindings: struct, tuple, array, dan iterasi map
// Kompilasi: g++ -std=c++23 -Wall -Wextra bindings.cpp -o bindings

#include <algorithm>
#include <map>
#include <print>
#include <string>
#include <tuple>
#include <vector>

struct MinMax {
    int kecil;
    int besar;
};

MinMax analisis(const std::vector<int>& v) {
    return {*std::ranges::min_element(v), *std::ranges::max_element(v)};
}

int main() {
    // 1) bongkar struct: dua kembalian tanpa variabel sementara
    std::print("-- struct: dua kembalian sekaligus\n");
    auto [terkecil, terbesar] = analisis({4, 9, 1, 7});
    std::print("min={} max={}\n", terkecil, terbesar);

    // 2) bongkar std::tuple: tiga tipe berbeda dalam satu deklarasi
    std::print("-- tuple: tiga tipe dalam satu deklarasi\n");
    std::tuple<int, std::string, double> hasil{200, "OK", 88.5};
    auto [kode, pesan, skor] = hasil;
    std::print("kode={} pesan={} skor={}\n", kode, pesan, skor);

    // 3) bongkar C-array: elemen bernama tanpa indeks
    std::print("-- array: elemen bernama tanpa indeks\n");
    int raw[3]{5, 6, 7};
    auto [a, b, c] = raw;
    std::print("a={} b={} c={}\n", a, b, c);

    // 4) binding by value vs binding referensi
    std::print("-- by value vs reference\n");
    std::pair<int, std::string> data{10, "MERAH"};
    auto [angka, warna] = data;          // salinan kedua elemen
    angka = 99;                          // mengubah salinan
    std::print("salinan  : angka={} data.first={}\n", angka, data.first);

    auto& [n, w] = data;                 // nama alternatif untuk member asli
    n = 42;                              // mengubah data.first sungguhan
    std::print("referensi: n={} data.first={}\n", n, data.first);

    // 5) use case utama: iterasi map dengan nama bermakna
    std::print("-- iterasi map\n");
    std::map<std::string, int> stok{{"beras", 9}, {"gandum", 3}, {"gula", 5}};
    for (const auto& [nama, jumlah] : stok) {
        std::print("{} = {}\n", nama, jumlah);
    }
    return 0;
}

Output yang Dihasilkan:

text
-- struct: dua kembalian sekaligus
min=1 max=9
-- tuple: tiga tipe dalam satu deklarasi
kode=200 pesan=OK skor=88.5
-- array: elemen bernama tanpa indeks
a=5 b=6 c=7
-- by value vs reference
salinan  : angka=99 data.first=10
referensi: n=42 data.first=42
-- iterasi map
beras = 9
gandum = 3
gula = 5

Mari kita bedah:

  1. Baris 23-24 (dua kembalian): fungsi analisis mengembalikan struct MinMax berisi nilai terkecil dan terbesar dalam satu kembalian — binding langsung memasangkannya ke terkecil dan terbesar. Pola “struct kecil sebagai kembalian” menggantikan trik lama parameter output (int& minOut), dan lebih enak dibaca di sisi pemanggil.
  2. Baris 28-30 (tuple tiga tipe): auto [kode, pesan, skor] = hasil; membongkar int, std::string, dan double dalam satu deklarasi — tiap nama otomatis bertipe elemen posisinya. Ini pasangan alami std::make_tuple saat kita belum ingin menulis struct khusus.
  3. Baris 34-36 (C-array): auto [a, b, c] = raw; memberi nama ke tiga elemen array polos — compiler tahu panjang array sehingga jumlah nama bisa diperiksa saat kompilasi.
  4. Baris 40-47 (by value vs referensi): auto [angka, warna] = data; menyalin kedua elemen, sehingga angka = 99 tidak menyentuh data (tercetak data.first=10). Sementara auto& [n, w] = data; membuat n menjadi nama alternatif data.first — n = 42 mengubah objek aslinya, terbukti dari data.first=42. Aturannya identik dengan tabel deduksi auto pada chapter deduksi: by value menyalin, & mengalias.
  5. Baris 51-54 (iterasi map): setiap elemen std::map adalah std::pair<const std::string, int>, sehingga const auto& [nama, jumlah] mengikat key dan value ke dua nama yang bermakna. Output terurut alfabetis karena std::map menjaga urutan key — perilaku yang sudah kita andalkan saat mencetak data terurut.

Aturan Modifier: Salin, Alias, atau Baca-saja #

Tiga bentuk binding mencakup hampir semua kebutuhan, dan pilihannya bisa dipandu pertanyaan sederhana: apakah kita akan membaca atau mengubah?

BentukEfekPakai saat
auto [a, b] = obj;salinan elemen; perubahan tidak menyentuh objbutuh kepemilikan sendiri / objek kecil
auto& [a, b] = obj;alias ke elemen asli; bisa mengubahakan memodifikasi data sumber
const auto& [a, b] = obj;alias baca-saja tanpa salinanpilihan default untuk membaca

Baris ketiga adalah default yang paling sering benar: iterasi map di atas memakainya karena kita hanya membaca, dan const di dalam tipe pair juga mencegah key std::map terubah — key yang berubah akan merusak urutan internal container. Bila kita memakai auto& untuk membaca tanpa mengubah, pembaca kode jadi bertanya-tanya apakah data akan dimodifikasi; sedangkan auto polos pada elemen berat (std::string, std::vector) berarti salinan penuh yang sering tidak disengaja — perilaku yang sama dengan auto biasa yang sudah kita bahas.

Use Case Utama: Iterasi map dan Kembalian Ganda #

Dua pola di program ini mewakili mayoritas pemakaian structured bindings di kode produksi. Yang pertama sudah kita lihat: iterasi std::map/std::unordered_map. Bandingkan bentuk lama for (const auto& entry : stok) std::print(entry.first, entry.second); — pembaca harus mengingat bahwa first artinya key dan second artinya value. Dengan const auto& [nama, jumlah], makna terbaca dari namanya sendiri, dan kesalahan tertukar key-value praktis mustahil terjadi tanpa terlihat.

Yang kedua adalah kembalian ganda. Sebelum C++17, fungsi yang ingin mengembalikan dua nilai terpaksa memilih antara parameter output, array yang tipe samanya, atau std::pair yang diakses .first/.second. Sekarang rantainya mulus: struct kecil (atau std::tuple) sebagai kembalian, binding di sisi pemanggil, dan tuple std::tie-style untuk mengabaikan elemen tertentu (auto [kode, pesan, skor] yang tidak dipakai tetap harus diberi nama — tak ada mekanisme _ bawaan, jadi namai dengan jelas). Kombinasi ini mengubah cara kita mendesain API kecil: fungsi bebas kaya informasi tanpa memaksa pemanggil berurusan dengan tipe antara.

Dari sini, perjalanan section Modern C++ melaju ke arah kontrol yang lebih presisi: chapter berikutnya membahas if constexpr, pernyataan percabangan yang dievaluasi saat kompilasi — alat yang pada program lambda bab lalu sudah kita lihat sekilas memilih jalur kode berdasarkan tipe.

Rujukan resmi: cppreference — structured binding declaration .