Menu

C++ Template'leri: Genel Fonksiyonlar ve Sınıflar Açıklandı

Kodu bir kez yazın ve C++ template'leri sayesinde her tür için çalışmasını sağlayın: fonksiyon template'leri, sınıf template'leri, tür çıkarımı ve neden olduğu kafa karıştırıcı derleyici hataları.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Bir Kez Yaz, Her Tür İçin Kullan

Önceki sayfada std::sort ile bir vector<int> sıraladınız. Ama std::sort aynı zamanda bir vector<string>, bir vector<double> ya da kendi struct'larınızdan oluşan bir diziyi de sıralar; üstelik her biri için ayrı bir sort yazan kimse olmadan. Bu ne bir sihir ne de aşırı yükleme (overloading). Bu bir template'tir: derleyicinin verdiğiniz her tür için yeniden kullandığı tek bir kod parçası.

Template'ler olmadan, her tür için aynı mantığı kopyala-yapıştır yapmaya mahkûm kalırdınız. İşte aynı maximum fonksiyonu üç kez yazılmış halde; template'lerin tam da yok etmek için var olduğu tekrarın ta kendisi:

int    maximum(int a, int b)       { return a > b ? a : b; }
double maximum(double a, double b) { return a > b ? a : b; }
string maximum(string a, string b) { return a > b ? a : b; }

Gövdeler birebir aynı. Yalnızca türler farklı. Bir template, "bu herhangi bir T türü için çalışır" demenizi ve onu bir kez yazmanızı sağlar.

Fonksiyon Template'leri

Bir fonksiyonu, önüne template <typename T> ekleyerek ve normalde somut bir türün geleceği her yerde T'yi kullanarak bir template'e dönüştürürsünüz.

Hiçbir zaman maximum<int> veya maximum<double> yazmadığınıza dikkat edin. Derleyici argümanlara bakar ve T'nin ne olması gerektiğini anlar; bu template argüman çıkarımıdır. Onu çağırdığınız her farklı tür, derleyicinin perde arkasında ayrı bir somut fonksiyon örneklemesine (üretmesine) yol açar.

Çıkarımın işe yaramadığı durumlarda, açılı parantezleri kullanarak türü açıkça belirtebilirsiniz:

Çıkarımda yaygın bir tuzak gizlidir. T tek bir tür olmak zorunda olduğundan, argüman türlerini karıştırmak çıkarımı bozar:

maximum(3, 7.5);   // HATA: T int mi yoksa double mı? Derleyici tahmin etmeyi reddeder.

Bunu açık olarak düzeltebilirsiniz - maximum<double>(3, 7.5) - ya da her parametreye kendi tür parametresini vererek; ki bunu birazdan yapacağız.

Birden Çok Tür Parametresi

Bir template tek bir türle sınırlı değildir. İhtiyacınız olduğu kadarını virgülle ayırarak listeleyin. Parametreleri farklı türlerde olabilen bir fonksiyonu işte böyle yazarsınız:

Dönüş türü parametrelere bağlı olduğunda, derleyicinin bunu auto ile (C++14 ve sonrası) çözmesine izin verin; bu template'lerle doğal biçimde uyumludur:

Sınıf Template'leri

Template'ler yalnızca fonksiyonlar için değildir; sınıfların tamamı da template haline getirilebilir. Standart konteynerler tam olarak böyle çalışır: vector<int>, anahtar-değer map ve pair<A, B> hepsi birer sınıf template'idir. Veri yapısını bir kez yazarsınız ve parametre olarak verdiğiniz türü saklar.

İşte herhangi bir türden tek bir değer tutan küçük, genel bir Box:

Fonksiyon template'lerinden temel farkı: bir sınıf template'inde türü genellikle açılı parantezler içinde vermeniz gerekir - Box<int> - çünkü eski standartlarda türü çıkarabileceğiniz constructor argümanları yoktur. (C++17, sınıf template argüman çıkarımını ekledi, böylece Box b(42); de çalışır; ama açık olmak her zaman güvenlidir ve net okunur.)

Hatalar Devasa Olacak - İşte Nedeni

Bu, herkesin takıldığı kısımdır, bu yüzden açıkça söylemekte fayda var. Bir template yalnızca gerçek bir türle örneklendiğinde tam olarak denetlenir. < kullanan bir template yazabilirsiniz ve o kendi başına sorunsuz derlenir; hata yalnızca onu < desteklemeyen bir türle örneklediğiniz anda ortaya çıkar.

template <typename T>
T maximum(T a, T b) {
    return a > b ? a : b;   // T'nin > işlemini desteklemesini gerektirir
}

struct Point { int x, y; };

// maximum(Point{1,2}, Point{3,4});
// HATA: Point için operator > yok. Mesaj hem Point'i adlandırır HEM DE
// bu fonksiyonun tamamını alıntılar, çoğu zaman birçok satıra yayılır.

Derleyici tam türü template'in içine yerleştirip hataları üretilen kodun içinden bildirdiğinden, tek bir hata kütüphane içlerinden söz eden bir çıktı duvarı üretebilir. İki hayatta kalma ipucu:

  • İlk hatayı okuyun, sonuncuyu değil. Sonraki hatalar genellikle ilkinin yan ürünüdür.
  • Mesajda kendi tür adınızı tarayın (burada Point). Bu, hangi örneklemenin yanlış gittiğini söyler.

Gerçek çözüm, türünüzün template'in ihtiyaç duyduğu her şeyi desteklediğinden emin olmaktır; maximum için bu, Point için operator>'ı aşırı yüklemek demektir ki o da sonraki bir sayfanın konusudur. Modern C++20 concept'leri bu hataları daha erkene çekip okunabilir hale getirebilir, ama altta yatan yerine koyma (substitution) modeli yine aynıdır.

Sıradaki: Sınıflar

Template'lere odaklanırken az önce bir Box sınıf template'i oluşturdunuz: özel verisi, bir constructor'ı ve üye fonksiyonları olan bir sınıf. Sonraki sayfa hızını düşürüp sınıfları gerektiği gibi öğretir: verileri, onlar üzerinde işlem yapan fonksiyonlarla nasıl bir araya getireceğinizi, public ile private'ın gerçekte neyi denetlediğini ve üye fonksiyonların nesnenin kendi durumuna nasıl eriştiğini. Gerçek C++'ta template'ler ve sınıflar sürekli birlikte kullanılır, bu yüzden sınıflara sağlam bir hâkimiyet genel kod yazmayı çok daha kolaylaştırır.

Sıkça Sorulan Sorular

C++'ta template nedir?

Template, bir fonksiyonu veya sınıfı bir kez yazıp, kullandığınız her tür için derleyicinin bir sürüm üretmesini sağlayan bir şablondur. template <typename T> yazarsınız ve ardından gerçek türün yerine T'yi kullanırsınız. Derleyici somut bir sürüm üretir; buna örnekleme (instantiation) denir.

Bir C++ template'inde typename ile class arasındaki fark nedir?

Bir template parametre listesinde template <typename T> ile template <class T> tam olarak aynı anlama gelir. Günümüzde genellikle typename tercih edilir çünkü daha dürüst okunur: T yalnızca bir sınıf değil, herhangi bir tür olabilir. Anahtar kelime seçimi üretilen kodu hiçbir şekilde etkilemez.

C++ template hata mesajları neden bu kadar uzun?

Template'ler yazıldıklarında değil, gerçek bir türle örneklendiklerinde denetlenir. Bir tür, kullandığınız bir işlemi (sıralama için < gibi) desteklemiyorsa, hata kütüphane kodunun derinliklerinde, örneklenen türün tamamı açıkça yazılmış halde ortaya çıkar ve sayfalarca çıktı üretir. İlk hatayı okuyun ve içinde kendi tür adınızı arayın.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA