İçindekiler
Aynı toplama, karşılaştırma veya sıralama işlemini int, double ve başka veri türleri için tekrar tekrar yazmak pek eğlenceli değildir. C++ şablonları, algoritmayı bir kez tanımlayıp onu farklı türlerle kullanmamızı sağlar. Böylece derleyici, ihtiyaç duyulan türe uygun kodu bizim için üretir; biz de kopyala-yapıştır bataklığından kurtuluruz.
``
Şablonların temel mantığı
Şablon, henüz kesinleşmemiş bir türü veya değeri parametre olarak alan kod kalıbıdır. T gibi bir şablon parametresi başlangıçta gerçek bir tür değildir; derleme sırasında int, double veya kullanıcı tarafından tanımlanmış bir sınıfla değiştirilir.
Bunu matematikteki genel bir fonksiyona benzetebiliriz:
\[f(x, y) = x + y\]Burada toplama işlemi, $x$ ve $y$ değerlerinin türünden çok + operatörünü destekleyip desteklemediğiyle ilgilenir. Şablonlar da benzer biçimde çalışır. Bir tür, şablonun kullandığı işlemleri sağlıyorsa o şablonla kullanılabilir.
| Yaklaşım | Avantaj | Dezavantaj |
|---|---|---|
| Her tür için ayrı fonksiyon | Okuması kolaydır | Kod tekrarı oluşturur |
void* kullanımı |
Türden bağımsız görünebilir | Tür güvenliği zayıftır |
| Şablon kullanımı | Tür güvenli ve yeniden kullanılabilirdir | Hata mesajları karmaşık olabilir |
Fonksiyon şablonları
İki değerden büyük olanı döndüren jenerik bir fonksiyon yazalım:
#include <iostream>
#include <string>
template <typename T>
T buyukOlan(const T& a, const T& b) {
return (a > b) ? a : b;
}
int main() {
std::cout << buyukOlan(12, 7) << '\n';
std::cout << buyukOlan(3.4, 8.1) << '\n';
std::cout << buyukOlan(std::string("Ali"), std::string("Zeynep"));
}
template <typename T> ifadesi, T adlı bir tür parametresi tanımlar. Derleyici ilk çağrıda T = int, ikinci çağrıda T = double kabul eder. Bu işleme şablon örnekleme denir. Kabaca üretilen fonksiyon sayısını şöyle düşünebiliriz:
Parametreleri const T& ile almak, özellikle büyük nesnelerin gereksiz yere kopyalanmasını önler. Ancak kullanılan türün > operatörünü desteklemesi gerekir; aksi hâlde derleme hatası alınır.
Birden fazla tür parametresi
Bazen giriş türleri birbirinden farklı olabilir:
template <typename T, typename U>
auto topla(const T& a, const U& b) {
return a + b;
}
int main() {
auto sonuc = topla(10, 2.5); // Sonuç double olur
}
auto dönüş türünü a + b ifadesinden çıkarır. Böylece int ve double birlikte kullanılabilir. Yine de sonuç, ilgili türlerin birbirleriyle toplanabilmesine bağlıdır.
Sınıf şablonları
Şablonlar yalnızca fonksiyonlar için değildir. Farklı türlerde değer saklayabilen basit bir kutu sınıfı oluşturalım:
#include <utility>
template <typename T>
class Kutu {
private:
T deger;
public:
explicit Kutu(T yeniDeger)
: deger(std::move(yeniDeger)) {}
const T& getir() const {
return deger;
}
void ayarla(const T& yeniDeger) {
deger = yeniDeger;
}
};
int main() {
Kutu<int> puan(100);
Kutu<std::string> mesaj("Merhaba şablon!");
}
Kutu<int> ve Kutu<std::string>, aynı sınıf şablonundan üretilmiş farklı sınıf türleridir. Derleyici bunların her biri için uygun alanları ve metotları oluşturur.
| Özellik | Fonksiyon şablonu | Sınıf şablonu |
|---|---|---|
| Tür çıkarımı | Genellikle otomatik | Çoğunlukla açıkça belirtilir |
| Kullanım amacı | Jenerik algoritmalar | Jenerik veri yapıları |
| Örnek | buyukOlan(3, 5) |
Kutu<int> |
Dikkat edilmesi gerekenler
Şablon tanımları çoğunlukla başlık dosyalarında bulunur. Çünkü derleyicinin belirli bir tür için kod üretirken şablonun tüm gövdesini görmesi gerekir. Ayrıca her tür, şablonda kullanılan operatörleri sağlamalıdır. Modern C++20 projelerinde bu beklentiler concept yapılarıyla açıkça ifade edilebilir.
Şablonlar; std::vector, std::map ve std::sort gibi Standart Kütüphane araçlarının temelidir. Kısacası doğru kullanıldıklarında daha az tekrar, güçlü tür güvenliği ve genişletilebilir kod sunarlar. Derleyici biraz daha çalışır, fakat programcı çok daha az terler!
Yorumlar