Template umum memperlakukan semua tipe dengan aturan yang sama, tetapi kadang satu tipe butuh pengecualian. Kotak<bool> mungkin ingin menampilkan “benar/salah” alih-alih angka; Kotak<const char*> mungkin ingin menyalin teks ke std::string alih-alih menyimpan pointer mentah yang rawan menggantung. C++ menyediakan mekanisme full specialization: definisi pengganti yang dipakai compiler bila argumen template mencocokkan satu tipe pasti. Pratinjau singkatnya sudah kita lihat di awal Section — sekarang kita menulisnya utuh, mengujinya, dan menetapkan kapan alat ini layak diambil.
Full Specialization untuk Satu Tipe #
Sintaks kuncinya dua bagian: template <> (daftar parameter template kosong, karena tipenya sudah pasti) diikuti nama class yang sudah “diisi” argumennya, misalnya Kotak<bool>. Setelah itu badan class boleh ditulis bebas — tidak wajib meniru bentuk template umumnya.
#include <iostream>
#include <string>
// Template umum: cetak biru untuk semua tipe
template <typename T>
class Kotak {
public:
explicit Kotak(const T& isi) : isi_{isi} {}
const T& isi() const { return isi_; }
void cetak() const { std::cout << "Kotak<T> berisi " << isi_ << "\n"; }
private:
T isi_;
};
// Full specialization untuk bool: perilaku khusus
template <>
class Kotak<bool> {
public:
explicit Kotak(bool isi) : isi_{isi} {}
bool isi() const { return isi_; }
void cetak() const {
std::cout << "Kotak<bool> berisi " << (isi_ ? "benar" : "salah") << "\n";
}
private:
bool isi_;
};
// Full specialization untuk const char*: simpan salinan aman sebagai std::string
template <>
class Kotak<const char*> {
public:
explicit Kotak(const char* isi) : isi_{isi} {}
const std::string& isi() const { return isi_; }
void cetak() const {
std::cout << "Kotak<const char*> menyimpan salinan: " << isi_ << "\n";
}
private:
std::string isi_;
};
int main() {
Kotak<int> angka{42};
Kotak<bool> bendera{true};
Kotak<const char*> teks{"Siti"};
angka.cetak();
bendera.cetak();
teks.cetak();
std::cout << "bendera: " << bendera.isi() << "\n";
std::cout << "panjang teks: " << teks.isi().size() << "\n";
return 0;
}Output yang Dihasilkan:
Kotak<T> berisi 42
Kotak<bool> berisi benar
Kotak<const char*> menyimpan salinan: Siti
bendera: 1
panjang teks: 4Bedah baris demi baris:
- Baris 5-14: template umum yang berlaku untuk semua tipe kecuali yang punya spesialisasi.
Kotak<int> angka{42}pada baris 45 jatuh ke sini. - Baris 17-18 (
template <> class Kotak<bool>): full specialization pertama. Bagi compiler,Kotak<bool>kini adalah class berdiri sendiri — boleh punya member, constructor, dan data member yang berbeda dari template umumnya. - Baris 22-24:
cetak()versi bool menampilkan teks “benar/salah” lewat conditional operator, bukan angka. Inilah “perilaku khusus per tipe” yang dimaksud. - Baris 31-32 (
template <> class Kotak<const char*>): full specialization kedua. Data membernya diubah menjadistd::string(baris 41) — keputusan penyimpanan yang berbeda dari template umum. - Baris 47 dan 54: pemanggil
teks.isi().size()bekerja karena versi spesialisasi mengembalikanconst std::string&— antarmuka yang lebih kaya dibanding pointer mentah. - Baris 53:
bendera.isi()mengembalikanbool, sehingga tercetak1tanpastd::boolalpha.
Kapan Spesialisasi Layak Dipakai #
Spesialisasi bukan alat sehari-hari, tetapi tiga situasi berikut sering muncul di kode profesional:
- Optimasi per tipe. Template umum berjalan benar untuk semua tipe, namun satu tipe punya algoritme yang jauh lebih cepat. Standard library melakukannya di banyak tempat, misalnya versi
std::copyuntuk tipe yang bisa disalin mentah denganmemcpy. - Penyelamatan tipe bermasalah. Contoh di atas:
const char*tidak punya semantik kepemilikan, jadi spesialisasi mengubahnya menjadistd::stringyang aman. Pola serupa: menyimpanboolsecara hemat dengan bit, atau menanganivoidyang menolak sebagian operasi. - Kunci ke standard library. Class buatan kita yang ingin jadi key pada
std::unordered_mapbutuhstd::hash<NamaKita>— dan cara resminya adalah full specialization dari templatestd::hashdi namespacestd(satu dari sedikit spesialisasi yang diizinkan standar di sana).
Spesialisasi Function Template #
Function template juga bisa dispesialisasi penuh. Kita kembali ke maks dari chapter pertama: untuk const char*, perbandingan > membandingkan alamat memori — hasilnya ditentukan posisi literal di memori, bukan urutan alfabet. Versi khusus memakai std::strcmp:
#include <cstring>
#include <iostream>
template <typename T>
T maks(T a, T b) {
return (a > b) ? a : b;
}
// Full specialization function template untuk const char*:
// bandingkan isi teks, bukan alamat memori
template <>
const char* maks<const char*>(const char* a, const char* b) {
return std::strcmp(a, b) > 0 ? a : b;
}
int main() {
std::cout << "angka : " << maks(3, 9) << "\n";
std::cout << "string: " << maks("jeruk", "apel") << "\n";
const char* hasil = maks<const char*>("kiwi", "mangga");
std::cout << "eksplisit: " << hasil << "\n";
return 0;
}Output yang Dihasilkan:
angka : 9
string: jeruk
eksplisit: manggaYang perlu dicermati:
- Baris 11-14 (
template <> const char* maks<const char*>(...)): bentuknya dekat dengan overloading biasa, tetapitemplate <>dan namamaks<const char*>menandakan ini spesialisasi — versi dari template yang sudah ada, bukan fungsi baru. - Baris 18: pemanggilan
maks("jeruk", "apel")tidak menyebut argumen template apa pun, namun compiler tetap memilih spesialisasi: argumenconst char[6]meluruh menjadiconst char*, dan pencarian menemukan spesialisasi untukT = const char*. - Baris 20: argumen eksplisit
maks<const char*>juga sah dan menghasilkan pemilihan yang sama. Hasilnya “mangga” — urutan alfabet, bukan alamat memori.
Satu catatan gaya: untuk function template, banyak programmer memilih overloading biasa (const char* maks(const char*, const char*)) karena aturan pemilihannya lebih sederhana dan tidak mudah salah urutan. Spesialisasi function template punya jebakan tersendiri yang berhubungan dengan overloading — dan karena function template sama sekali tidak mendukung partial specialization, pilihan alternatifnya menjadi penting. Kita bongkar semuanya pada Chapter Partial Specialization.
Referensi resmi: cppreference — Template specialization dan cppreference — std::hash .