Section ini membuka babak baru: dari pengguna kode menjadi penulis kode generik. Pada Section Fungsi kita sudah membuat satu function template sederhana bernama maks — sekarang kita membongkarnya lebih dalam: template dengan beberapa parameter tipe, return type yang dideduksi compiler, dan sekilas kemampuan memberi perilaku khusus untuk tipe tertentu. Semua mekanisme ini bekerja penuh pada saat kompilasi, sehingga fleksibilitas yang kita dapat tidak menambah biaya apa pun saat program berjalan. Kuasai chapter ini dengan baik, karena empat belas chapter ke depan semuanya berdiri di atasnya.

Recap: Satu Definisi untuk Banyak Tipe #

Ingat kembali pola dasarnya. template <typename T> membuka daftar parameter template, lalu T dipakai sebagai nama tipe di dalam signature fungsi. Compiler tidak mengompilasi template apa adanya; ia menunggu pemanggilan, mendeduksi T dari argumen, lalu menginstansiasi fungsi sebenarnya untuk tipe tersebut.

cpp
#include <iostream>
#include <string>

// Recap: satu parameter tipe T, persis seperti pengantar di Section Fungsi
template <typename T>
T maks(T a, T b) {
    return (a > b) ? a : b;
}

// Pendalaman: dua parameter tipe, A dan B boleh berbeda
template <typename A, typename B>
void cetakPasangan(const A& pertama, const B& kedua) {
    std::cout << "(" << pertama << ", " << kedua << ")\n";
}

// Return type tidak ditulis manual; compiler mendeduksinya dari return
template <typename A, typename B>
auto kali(A a, B b) {
    return a * b;
}

int main() {
    std::cout << "maks(10, 3)  -> " << maks(10, 3) << "\n";
    std::cout << "maks(string) -> " << maks(std::string("kiwi"), std::string("apel")) << "\n";

    cetakPasangan(7, "tujuh");
    cetakPasangan(2.5, 'X');

    std::cout << "kali(3, 4)   -> " << kali(3, 4) << "\n";
    std::cout << "kali(3, 0.5) -> " << kali(3, 0.5) << "\n";

    return 0;
}

Output yang Dihasilkan:

text
maks(10, 3)  -> 10
maks(string) -> kiwi
(7, tujuh)
(2.5, X)
kali(3, 4)   -> 12
kali(3, 0.5) -> 1.5

Mari kita bedah baris demi baris:

  1. Baris 5-8 (T maks(T a, T b)): cetak biru yang sudah kita kenal. Pemanggilan maks(10, 3) pada baris 23 menginstansiasi maks<int>, sedangkan baris 24 menginstansiasi maks<std::string> — dua fungsi berbeda dari satu definisi. Perbandingan string menghasilkan kiwi karena operator> pada std::string bekerja leksikografis.
  2. Baris 11-14 (void cetakPasangan(const A&, const B&)): template ini punya dua parameter tipe. Pemanggilan cetakPasangan(7, "tujuh") menduksi A = int dan B = const char*; tipe yang berbeda tidak lagi menjadi masalah karena masing-masing punya parameter sendiri.
  3. Baris 18-20 (auto kali(A a, B b)): return type tidak ditulis; compiler menyimpulkannya dari pernyataan return. Dari kali(3, 4) lahir fungsi yang menghasilkan int, sedangkan kali(3, 0.5) menghasilkan double karena 3 * 0.5 bertipe double.
  4. Baris 26-27: parameter template dikirim sebagai const A& — pengiriman lewat reference menghindari penyalinan object besar, kebiasaan yang juga dipakai standard library.

Dua Parameter Tipe atau Lebih #

Daftar parameter template bisa memuat sebanyak mungkin parameter, dipisah koma, persis seperti daftar parameter fungsi. Setiap parameter harus terpakai dalam signature agar bisa dideduksi, atau diberi nilai eksplisit saat pemanggilan seperti kali<double, double>(3, 4). Dalam praktik, template dengan dua hingga tiga parameter tipe sangat lazim — std::pair misalnya punya dua — sedangkan yang lebih banyak biasanya menandakan desain yang patut ditinjau ulang.

Return type eksplisit juga tetap bisa ditulis bila kita ingin menentukan sendiri hasilnya. Alternatif modernnya adalah trailing return type: auto kali(A a, B b) -> decltype(a * b) memakai decltype untuk mendeklarasikan tipe hasil ekspresi a * b tanpa harus mengetahuinya di depan. Bentuk auto polos (C++14 ke atas) lebih ringkas dan cukup untuk kebanyakan kasus.

cpp Konflik deduksi return type (tidak dikompilasi)
template <typename T>
auto pilih(T a, T b) {
    if (a > b) return a;
    return a * 1.5;  // int lalu double — konflik
}

int main() {
    pilih(3, 2); // instansiasi memicu deduksi return type
}

Pesan yang keluar dari g++ 14.2:

text
konflik-auto.cpp: In instantiation of 'auto pilih(T, T) [with T = int]':
konflik-auto.cpp:8:10:   required from here
    8 |     pilih(3, 2); // instansiasi memicu deduksi return type
      |     ~~~~~^~~~~~
konflik-auto.cpp:4:14: error: inconsistent deduction for auto return type: 'int' and then 'double'
    4 |     return a * 1.5;  // int lalu double — konflik
      |            ~~^~~~~

Perhatikan urutan laporannya: compiler menunjuk pemanggilan di main sebagai pemicu instansiasi, lalu titik persisnya konflik. Pola “required from here” seperti ini akan menemani kita sepanjang Section, jadi biasakan membacanya dari bawah ke atas.

Pratinjau: Spesialisasi Eksplisit #

Template menerima semua tipe secara setara, tetapi kadang satu tipe butuh perlakuan istimewa. Contohnya maks("jeruk", "apel"): dengan T = const char*, operator> membandingkan alamat memori, bukan isi teks. C++ menyediakan full specialization — definisi khusus untuk satu tipe pasti — yang ditulis dengan template <>:

cpp Bentuk spesialisasi eksplisit (pratinjau)
#include <cstring>

template <typename T>
T maks(T a, T b) {
    return (a > b) ? a : b;
}

// Versi khusus untuk const char*: bandingkan isi string
template <>
const char* maks(const char* a, const char* b) {
    return std::strcmp(a, b) > 0 ? a : b;
}

Sintaks ini sah dan bisa dikompilasi; compiler memilih versi khusus tersebut setiap kali maks dipanggil dengan dua const char*. Kita tidak membahas aturan lengkapnya sekarang — Chapter Template Specialization membuktikannya dengan kode yang diuji dan menunjukkan kapan spesialisasi layak dipakai.

Dengan rekapan tipe dan return type yang sudah rapat, kita siap naik satu tingkat: membuat bukan hanya fungsi, tetapi class yang generik. Chapter berikutnya membangun Kotak<T> — cetak biru class yang menjadi bahan latihan Section ini — dan mengenal std::vector<T> sebagai class template paling terkenal di dunia C++.

Referensi resmi: cppreference — Templates dan cppreference — Function template .