Şablon Özelleştirme
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 66 / 104.
Bazen genel bir şablon her tür için iyi çalışmaz. Örneğin, C stili dizeleri > ile karşılaştırmak, gerçek metni değil, işaretçi adreslerini karşılaştırır. Şablon özelleştirme (Template specialization), diğer her şey için genel sürümü korurken belirli türler için özel bir uygulama sunmanıza olanak tanır.
Bir tam özelleştirme (full specialization), belirli bir tür için tüm şablonun yerini alır. Bunu boş bir şablon parametre listesi ile bildirirsiniz ve somut türü belirtirsiniz:
// Birincil şablon
template <typename T>
class Printer {
public:
void print(T value) {
std::cout << value << std::endl;
}
};
// const char* için tam özelleştirme
template <>
class Printer<const char*> {
public:
void print(const char* value) {
std::cout << "String: " << value << std::endl;
}
};
Printer<int> intPrinter;
intPrinter.print(42); // Çıktı: 42
Printer<const char*> strPrinter;
strPrinter.print("hello"); // Çıktı: String: helloFonksiyon şablonları da özelleştirilebilir:
template <typename T>
bool isEqual(T a, T b) {
return a == b;
}
template <>
bool isEqual<const char*>(const char* a, const char* b) {
return std::strcmp(a, b) == 0;
}
isEqual(5, 5); // Genel sürümü kullanır
isEqual("hi", "hi"); // Özelleştirilmiş sürümü kullanırDerleyici her zaman en spesifik eşleşmeyi tercih eder; kullanılan tam tür için bir özelleştirme (specialization) mevcutsa, genel şablon (generic template) yerine bu seçilecektir.
Görev
KolayŞablon özelleştirmenin (template specialization), diğer her şey için genel bir geri dönüş mekanizmasını korurken belirli türler için davranışı nasıl özelleştirmenize olanak tanıdığını gösteren, türe duyarlı bir biçimlendirici (formatter) sistemi oluşturalım.
Şablon kodunuzu düzenlemek için iki dosya oluşturacaksınız:
Formatter.h: Değerleri görüntülemek üzere biçimlendirenFormatteradında bir sınıf şablonu tanımlayın. Genel şablonunuz her türle çalışmalıdır, ancak özel işlem gerektiren türler için özelleştirilmiş sürümler de oluşturacaksınız.Birincil
Formatterşablonu şunlara sahip olmalıdır:- T türünde bir değer alan ve şunu yazdıran bir
format()yöntemi:Value: <value>
1 veya 0 yerine insan tarafından okunabilir metin yazdıran
booliçin tam bir özelleştirme oluşturun:format()yöntemi şunu yazdırmalıdır:Boolean: trueveyaBoolean: false
Dizelerin etrafına tırnak işaretleri ekleyen
const char*için tam bir özelleştirme oluşturun:format()yöntemi şunu yazdırmalıdır:String: "<value>"
Ayrıca, aynı türden iki değer alan ve bunları birlikte şu şekilde yazdıran
formatPairadında bir fonksiyon şablonu oluşturun:Pair: [<first>, <second>]Her dizeyi tırnak içine alan
const char*için birformatPairözelleştirmesi oluşturun:Pair: ["<first>", "<second>"]- T türünde bir değer alan ve şunu yazdıran bir
main.cpp: Dört girdi okuyun (her biri ayrı bir satırda):- Bir tam sayı (integer)
- Bir ondalıklı sayı (double)
- Dize olarak bir boolean (
"true"veya"false") - Bir dize değeri
Uygun
Formatternesneleri oluşturarak ve her tür içinformat()yöntemini çağırarak biçimlendiricilerinizi gösterin:Formatter<int>kullanarak tam sayıyı biçimlendirinFormatter<double>kullanarak ondalıklı sayıyı biçimlendirinFormatter<bool>kullanarak boolean değerini biçimlendirin (önce dize girdisini bir bool değerine dönüştürün)Formatter<const char*>kullanarak dizeyi biçimlendirin
Ardından fonksiyon şablonu özelleştirmesini gösterin:
- İki tam sayı ile
formatPairfonksiyonunu çağırın: 10 ve 20 - İki C-dizesi ile
formatPairfonksiyonunu çağırın:"hello"ve"world"
Örneğin, 42, 3.14, "true" ve "Hello" girdileriyle:
Value: 42
Value: 3.14
Boolean: true
String: "Hello"
Pair: [10, 20]
Pair: ["hello", "world"]Genel şablonun tam sayıları ve ondalıklı sayıları aynı şekilde nasıl işlediğine, bool ve const char* için özelleştirilmiş sürümlerin ise nasıl özel biçimlendirme sağladığına dikkat edin. Derleyici, kullandığınız her tür için otomatik olarak en spesifik eşleşmeyi seçer.
Kopya kağıdı
Şablon özelleştirme (template specialization), diğer tüm türler için genel bir sürümü korurken, belirli türler için özel uygulamalar sağlamanıza olanak tanır.
Tam Özelleştirme Sözdizimi
Boş bir şablon parametre listesi template <> ile bir özelleştirme bildirin ve somut türü belirtin:
// Primary template
template <typename T>
class Printer {
public:
void print(T value) {
std::cout << value << std::endl;
}
};
// Full specialization for const char*
template <>
class Printer<const char*> {
public:
void print(const char* value) {
std::cout << "String: " << value << std::endl;
}
};
Fonksiyon Şablonu Özelleştirme
Fonksiyon şablonları da özelleştirilebilir:
template <typename T>
bool isEqual(T a, T b) {
return a == b;
}
template <>
bool isEqual<const char*>(const char* a, const char* b) {
return std::strcmp(a, b) == 0;
}
Derleyici Seçimi
Derleyici her zaman en spesifik eşleşmeyi tercih eder - eğer kullanılan tam tür için bir özelleştirme mevcutsa, genel şablona göre bu tercih edilecektir.
Kendin dene
#include <iostream>
#include <string>
#include "Formatter.h"
using namespace std;
int main() {
// Girdileri oku
int intVal;
double doubleVal;
string boolStr;
string strVal;
cin >> intVal;
cin >> doubleVal;
cin >> boolStr;
cin >> strVal;
// Dizeyi bool değerine dönüştür
bool boolVal = (boolStr == "true");
// TODO: Formatter<int> oluştur ve tam sayıyı formatla
// TODO: Formatter<double> oluştur ve ondalıklı sayıyı formatla
// TODO: Formatter<bool> oluştur ve boolean değerini formatla
// TODO: Formatter<const char*> oluştur ve dizeyi formatla
// İpucu: const char* elde etmek için strVal.c_str() kullanın
// TODO: formatPair fonksiyonunu iki tam sayı ile çağır: 10 ve 20
// TODO: formatPair fonksiyonunu iki C-dizesi ile çağır: "hello" ve "world"
return 0;
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic Konteyner