Menuliskan tipe secara eksplisit memang disiplin yang baik, tetapi ada situasi di mana tipe itu panjang, repetitif, atau bahkan sulit ditulis dengan benar. Kata kunci auto — resmi untuk keperluan ini sejak C++11 — memindahkan pekerjaan itu kepada compiler: kita menulis auto nama = nilai;, dan compiler menetapkan tipe nama persis dari nilai yang kita berikan. Bukan keajaiban dan bukan tipe “apa saja”: deduksi auto punya aturan yang tegas, dan memahami aturannya penting karena ada kasus di mana const atau reference ternyata tidak ikut terbawa. Chapter ini membedah aturan itu lewat program teruji, syarat wajib initializer, dan mengakhiri dengan sekilas pandang decltype sebagai pasangannya.
auto untuk Variabel #
Sebelum membaca contoh, satu konteks singkat: baris int& aliasUmur = umur; di bawah membuat reference — nama lain untuk variabel yang sama, bukan salinan — yang pembahasannya tuntas di Section Pointer dan Reference. Kita memakainya di sini hanya untuk membuktikan bagaimana auto memperlakukannya. Sekarang programnya:
#include <iostream>
#include <string>
int main() {
int umur = 20;
const int batasUsia = 100;
auto a = umur; // int: salinan dari umur
auto b = batasUsia; // int: const tidak terbawa ke salinan
auto c = 3.14; // double
auto d = 10u; // unsigned int
auto e = "C++23"; // const char*: string literal, BUKAN std::string
auto f = std::string{"auto"};
int& aliasUmur = umur; // reference: nama lain untuk umur
auto g = aliasUmur; // int: reference ikut hilang saat disalin
auto& rUmur = aliasUmur; // int&: auto& mempertahankan reference
const auto& rBatas = batasUsia; // const int&: const terjaga lewat referensi
decltype(batasUsia) salinanBatas = batasUsia; // const int: dipertahankan persis
b = 150; // sah: b hanyalah int biasa
std::cout << "a = " << a << "\n";
std::cout << "b = " << b << "\n";
std::cout << "c = " << c << "\n";
std::cout << "d = " << d << "\n";
std::cout << "e = " << e << "\n";
std::cout << "f = " << f << "\n";
std::cout << "g = " << g << "\n";
std::cout << "rUmur = " << rUmur << "\n";
std::cout << "rBatas = " << rBatas << "\n";
std::cout << "salinan = " << salinanBatas << "\n";
return 0;
}Output yang Dihasilkan:
a = 20
b = 150
c = 3.14
d = 10
e = C++23
f = auto
g = 20
rUmur = 20
rBatas = 100
salinan = 100Setiap variabel auto di atas menerima tipe dari initializer-nya: a dari int, c dari literal 3.14 yang bertipe double, d dari literal 10u yang bertipe unsigned int (tercetak 10, sebagaimana perilaku tampilan unsigned), dan f dari std::string. Baris b = 150; adalah bukti perilaku paling penting: b dideduksi dari batasUsia yang const, tetapi yang terdeduksi hanyalah int biasa — assignment justru berhasil dan b berubah menjadi 150.
Aturan Deduksi auto #
Perilaku di atas bukan acakan; standar menetapkannya dengan aturan yang bisa diringkas untuk variabel:
auto x = nilai;membuat salinan: tipexadalah tipenilaisetelah referensi dan const tingkat teratas dilepas. Karena ituauto b = batasUsia;menghasilkanint— kita mendapat salinan yang boleh diubah, bukan cermin dari variabel const-nya.- Reference ikut hilang saat disalin:
auto g = aliasUmur;menghasilkanint, bukanint&. Salinan memang salinan; mengubahgtidak menyentuhumur. auto&mempertahankan reference: menambahkan&memaksa deduksi mengikuti bentuk referensi, sehinggarUmuradalah nama lain yang nyata untukumur.const auto&menjaga const:rBatasbertipeconst int&; melalui nama ini,batasUsiatetap tidak bisa diubah.- Tipe mengikuti literal apa adanya:
3.14berartidouble(bukanfloat),10uberartiunsigned int, dan"C++23"berarticonst char*— string literal bertipe karakter mentah, bukanstd::string. Itulah jebakanauto eyang paling sering menggigit pemula; jika inginstd::string, tulis eksplisit atau pakaistd::string{"..."}.
Aturan “reference dan const hilang pada salinan” ini sebenarnya pindahan dari aturan konversi yang sama yang kita temui pada Chapter Signed dan Unsigned: compiler mengikuti aturan baku bahasa, dan auto hanya menerapkannya secara konsisten. Konsekuensi praktisnya: gunakan auto saat Anda memang sengaja menginginkan salinan, dan pakai auto& atau const auto& ketika ingin berbagi objek yang sama.
auto Wajib Punya Initializer #
Deduksi bekerja dengan cara membaca nilai awal, sehingga auto tanpa initializer tidak punya bahan berpikir dan compiler langsung menolaknya:
int main() {
auto x;
return 0;
}Pesan yang dihasilkan g++:
auto-noinit.cpp: In function ‘int main()’:
auto-noinit.cpp:2:5: error: declaration of ‘auto x’ has no initializer
2 | auto x;
| ^~~~Syarat ini sebenarnya menyelamatkan kita dari masalah lama: variabel yang dideklarasikan tanpa nilai (Chapter Deklarasi Variabel). Dengan auto, lupa memberi nilai awal tidak lagi mungkin lolos diam-diam — compiler menjadi penjaga yang memaksa pola “deklarasi sekaligus inisialisasi” yang kita anjurkan sejak awal section ini.
decltype: Deduksi Tanpa Menyalin #
auto punya pasangan bernama decltype. Bila auto mengambil tipe dari nilai initializer (lalu melepas reference dan const), decltype(nama) mengambil tipe persis seperti yang dideklarasikan untuk nama itu — const dan segalanya ikut. Pada contoh utama tadi, decltype(batasUsia) salinanBatas = batasUsia; mendeklarasikan variabel bertipe const int, persis tipe batasUsia, sehingga salinanBatas juga tidak boleh diubah. Aturan perbedaannya: auto menjawab “tipe apa yang pantas untuk salinan nilai ini”, sementara decltype menjawab “tipe apa yang tertulis pada entitas ini”. Pemakaian lanjutannya — misalnya menuliskan tipe kembalian fungsi — akan berguna setelah kita belajar fungsi di Section berikutnya; untuk sekarang cukup mengenali bentuknya.
auto paling bersinar ketika tipe sudah jelas dari konteks dan menulisnya hanya menambah kebisingan — pola yang akan makin sering muncul begitu kita masuk ke container pustaka standar. Namun ada satu kategori variabel yang justru kebalikannya: variabel yang nilainya tidak boleh berubah sama sekali. Untuk itulah const dan constexpr hadir, dan keduanya menjadi bahan Chapter berikutnya.
Rujukan resmi untuk topik Chapter ini: auto specifier dan decltype di cppreference.