Sejauh ini semua parameter template yang kita tulis menerima tipe. Padahal daftar parameter template juga bisa menerima nilai: angka, enum, pointer, bahkan nullptr. Parameter semacam ini disebut non-type template parameter (NTTP). Kita sebenarnya sudah memakainya di hampir setiap latihan array: angka 5 pada std::array<int, 5> adalah NTTP. Chapter ini membangun NTTP versi sendiri, membuktikan mengapa ukuran yang tersimpan di dalam tipe begitu berguna, dan menunjukkan bentuk template <auto V> dari C++17 yang mendeduksi jenis nilainya sendiri.
Nilai sebagai Parameter Template #
Contoh berikut membangun Buffer<T, N> — wadah dengan kapasitas tetap yang diketahui compiler. Perhatikan bahwa N dipakai seperti konstanta biasa di dalam class: sebagai ukuran std::array sekaligus nilai kembalian kapasitas().
#include <array>
#include <iostream>
// Parameter kedua bukan tipe, melainkan nilai: ukuran buffer
template <typename T, std::size_t N>
class Buffer {
public:
constexpr std::size_t kapasitas() const { return N; }
void isi(std::size_t indeks, const T& nilai) { data_[indeks] = nilai; }
const T& ambil(std::size_t indeks) const { return data_[indeks]; }
private:
std::array<T, N> data_{}; // std::array butuh ukuran pada saat kompilasi
};
// auto NTTP (C++17): jenis nilai dideduksi dari argumennya
template <auto V>
void cetakNilai() {
std::cout << V << "\n";
}
int main() {
Buffer<int, 5> buffer;
for (std::size_t i = 0; i < buffer.kapasitas(); ++i) {
buffer.isi(i, static_cast<int>(i) * 10);
}
std::cout << "kapasitas buffer : " << buffer.kapasitas() << "\n";
std::cout << "elemen [2] : " << buffer.ambil(2) << "\n";
std::array<int, 5> nilai{1, 2, 3, 4, 5}; // std::array: NTTP paling terkenal
std::cout << "ukuran array : " << nilai.size() << "\n";
cetakNilai<42>(); // V = int 42
cetakNilai<'x'>(); // V = char 'x'
cetakNilai<true>(); // V = bool true (tercetak 1)
constexpr std::size_t ukuran = 3; // konstanta compile time boleh jadi argumen
Buffer<double, ukuran> kecil;
std::cout << "kapasitas kecil : " << kecil.kapasitas() << "\n";
return 0;
}Output yang Dihasilkan:
kapasitas buffer : 5
elemen [2] : 20
ukuran array : 5
42
x
1
kapasitas kecil : 3Bedah bagian pentingnya:
- Baris 5 (
template <typename T, std::size_t N>): daftar parameter kini bercampur —Tuntuk tipe,Nuntuk nilai bertipestd::size_t. Setiap instansiasiBuffer<int, 5>danBuffer<int, 3>adalah class berbeda denganNyang “tercetak” ke dalam tipenya. - Baris 8 (
constexpr std::size_t kapasitas()): karenaNkonstanta compile time, fungsi ini ditandaiconstexpr— hasilnya bisa dipakai dalam ekspresi lain yang butuh konstanta, misalnya mendeklarasikan array baru. - Baris 13 (
std::array<T, N> data_{}): inilah keuntungan sesungguhnya. Kapasitas tersimpan dalam tipe, bukan dalam data member terpisah, sehingga tidak ada memori ekstra untuk menyimpan ukuran dan tidak ada kemungkinan ukuran berubah diam-diam. - Baris 17-20 (
template <auto V>): NTTP otomatis dari C++17.cetakNilai<42>()menduksiV = 42bertipeint;cetakNilai<'x'>()menduksichar;cetakNilai<true>()menduksibool. Satu template, banyak jenis nilai. - Baris 36:
truetercetak1karenaoperator<<default untuk bool menampilkan angka; tambahkanstd::boolalphabila ingin melihattrue. - Baris 38-39: variabel
constexprsah sebagai argumen NTTP karena nilainya pasti pada saat kompilasi.
std::array: NTTP yang Sudah Kita Pakai #
std::array<int, 5> membaca: “class template std::array diinstansiasi dengan tipe int dan nilai 5”. Dua argumen itu membentuk tipe yang berbeda total dari std::array<int, 10> — itulah sebabnya keduanya tidak bisa ditukar langsung, dan itulah sebabnya size() milik std::array bisa berupa constexpr tanpa menyimpan angka terpisah di dalam object. Bandingkan dengan std::vector<int> yang menyimpan ukuran di dalam data membernya: fleksibel saat runtime, tetapi membayar biaya penyimpanan dan alokasi.
Pola “ukuran di dalam tipe” ini laris di kode nyata: std::span<int, 5> (span berukuran tetap), dimension pada std::mdspan, dan berbagai math library template memakai NTTP untuk ukuran matriks sehingga kesalahan dimensi tertangkap compiler, bukan saat program berjalan.
auto NTTP dan Konstanta constexpr #
Bentuk template <auto V> menyerahkan jenis nilai kepada compiler — praktis ketika satu template harus menerima berbagai jenis konstanta tanpa kita menulis template <int V>, template <char V>, dan seterusnya satu per satu. Sejak C++20, batasannya melonggar: literal class types dengan anggota tertentu (misalnya std::pair sederhana atau class custom dengan anggota constexpr-friendly) pun bisa menjadi NTTP, membuka gaya template seperti template <std::pair<int, int> P>. Untuk tipe dasar, aturannya tetap: integral, enum, pointer, reference, dan nullptr_t.
Nilai yang dikirim sebagai NTTP wajib diketahui pada saat kompilasi. Variabel biasa — bahkan yang kebetulan sudah diisi angka — ditolak compiler:
#include <array>
#include <cstddef>
template <typename T, std::size_t N>
class Buffer {
private:
std::array<T, N> data_{};
};
int main() {
std::size_t n = 5; // nilai runtime
Buffer<int, n> b;
}Pesan nyata dari g++ 14.2:
nttp-err.cpp: In function 'int main()':
nttp-err.cpp:12:18: error: the value of 'n' is not usable in a constant expression
12 | Buffer<int, n> b;
| ^
nttp-err.cpp:11:17: note: 'std::size_t n' is not const
11 | std::size_t n = 5; // nilai runtime
| ^
nttp-err.cpp:12:18: note: in template argument for type 'long unsigned int'
12 | Buffer<int, n> b;
| ^Pesan 'n' is not const adalah inti aturannya: tambahkan constexpr pada n dan kode langsung sah. Juga perlu diketahui, double tidak boleh langsung menjadi NTTP karena representasi floating point tidak stabil antar platform — standar menutup celah itu hingga C++20 menyediakan jalan bawah berupa class type. Butuh ukuran mengambang? Simpan sebagai nilai integral (misalnya bilangan tetap) atau pakai konstanta lain.
Dengan tipe dan nilai kini berdampingan di daftar parameter template, satu pertanyaan menyusul secara alami: bagaimana bila satu tipe tertentu membutuhkan definisi yang berbeda dari cetak biru umum? Jawabnya adalah specialization — topik chapter berikutnya.
Referensi resmi: cppreference — Template parameters dan cppreference — std::array .