Şablonlar (C++)
Şablonlar, C++ dilinde genel programlama için temel oluşturur. Kesin olarak belirlenmiş bir dil olarak, C++ tüm değişkenlerin programcı tarafından açıkça bildirilen veya derleyici tarafından oluşturulan belirli bir türe sahip olmasını gerektirir. Ancak, birçok veri yapısı ve algoritma, hangi tür üzerinde çalışırlarsa olsunlar aynı görünür. Şablonlar, bir sınıfın veya işlevin işlemlerini tanımlamanızı ve kullanıcının bu işlemlerin hangi somut türlerde çalışacağını belirtmesini sağlar.
Şablonları tanımlama ve kullanma
Şablon, kullanıcının şablon parametreleri için sağladığı bağımsız değişkenlere göre derleme zamanında sıradan bir tür veya işlev oluşturan bir yapıdır. Örneğin, aşağıdaki gibi bir işlev şablonu tanımlayabilirsiniz:
template <typename T>
T minimum(const T& lhs, const T& rhs)
{
return lhs < rhs ? lhs : rhs;
}
Yukarıdaki kod, dönüş değeri ve çağrı parametrelerinin (lhs ve rhs) tümü bu tür olan tek tür parametreli bir genel işlev için bir şablon açıklar. Tür parametresini istediğiniz şekilde adlandırabilirsiniz, ancak kurala göre tek büyük harfler en yaygın olarak kullanılır. T bir şablon parametresidir; typename
anahtar sözcüğü bu parametrenin bir tür için yer tutucu olduğunu söyler. İşlev çağrıldığında, derleyici her örneğini T
kullanıcı tarafından belirtilen veya derleyici tarafından oluşturulan somut tür bağımsız değişkeniyle değiştirir. Derleyicinin şablondan bir sınıf veya işlev oluşturduğu işlem, şablon örneği oluşturma olarak adlandırılır; minimum<int>
şablonun minimum<T>
bir örneğidir.
Başka bir yerde, kullanıcı int için özelleştirilmiş bir şablon örneği bildirebilir. get_a() ve get_b() işlevlerinin int döndüren işlevler olduğunu varsayalım:
int a = get_a();
int b = get_b();
int i = minimum<int>(a, b);
Ancak, bu bir işlev şablonu olduğundan ve derleyici a ve b bağımsız değişkenlerinden türünü T
çıkarabildiğinden, bunu sıradan bir işlev gibi çağırabilirsiniz:
int i = minimum(a, b);
Derleyici bu son deyimle karşılaştığında, şablondaki her T örneğinin ile int
değiştirildiği yeni bir işlev oluşturur:
int minimum(const int& lhs, const int& rhs)
{
return lhs < rhs ? lhs : rhs;
}
Derleyicinin işlev şablonlarında tür kesintisi gerçekleştirme kuralları, sıradan işlevlerin kurallarına bağlıdır. Daha fazla bilgi için bkz . İşlev Şablonu Çağrılarının Aşırı Yükleme Çözümlemesi.
Tür parametreleri
Yukarıdaki şablondaminimum
, T tür parametresinin, const ve başvuru niteleyicilerinin eklendiği işlev çağrısı parametrelerinde kullanılana kadar hiçbir şekilde nitelenmediğini unutmayın.
Tür parametrelerinin sayısı için pratik bir sınır yoktur. Birden çok parametreyi virgülle ayırın:
template <typename T, typename U, typename V> class Foo{};
anahtar sözcüğü class
bu bağlamdaki ile typename
eşdeğerdir. Önceki örneği şu şekilde ifade edebilirsiniz:
template <class T, class U, class V> class Foo{};
Rastgele sayıda sıfır veya daha fazla tür parametresi alan bir şablon tanımlamak için üç nokta işlecini (...) kullanabilirsiniz:
template<typename... Arguments> class vtclass;
vtclass< > vtinstance1;
vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;
Yerleşik veya kullanıcı tanımlı herhangi bir tür, tür bağımsız değişkeni olarak kullanılabilir. Örneğin, Standart Kitaplık'ta std::vector kullanarak , , double
std::string, MyClass
, const
MyClass
*, MyClass&
ve benzeri türdeki int
değişkenleri depolayabilirsiniz. Şablonları kullanırken birincil kısıtlama, tür bağımsız değişkeninin tür parametrelerine uygulanan tüm işlemleri desteklemesi gerektiğidir. Örneğin, bu örnekte olduğu gibi kullanarak MyClass
öğesini çağırırsakminimum
:
class MyClass
{
public:
int num;
std::wstring description;
};
int main()
{
MyClass mc1 {1, L"hello"};
MyClass mc2 {2, L"goodbye"};
auto result = minimum(mc1, mc2); // Error! C2678
}
İşleç için < aşırı yükleme sağlamadığından bir derleyici hatası oluşturulurMyClass
.
Belirli bir şablon için tür bağımsız değişkenlerinin tümünün aynı nesne hiyerarşisine ait olması gerekmez, ancak böyle bir kısıtlamayı zorunlu kılan bir şablon tanımlayabilirsiniz. Nesne odaklı teknikleri şablonlarla birleştirebilirsiniz; örneğin, türetilmiş* bir vektör<Tabanında*> depolayabilirsiniz. Bağımsız değişkenlerin işaretçi olması gerektiğini unutmayın
vector<MyClass*> vec;
MyDerived d(3, L"back again", time(0));
vec.push_back(&d);
// or more realistically:
vector<shared_ptr<MyClass>> vec2;
vec2.push_back(make_shared<MyDerived>());
ve diğer standart kitaplık kapsayıcılarının öğelerine T
uyguladığı temel gereksinimlerstd::vector
, kopya atanabilir ve kopya oluşturulabilir olmasıdırT
.
Tür olmayan parametreler
C# ve Java gibi diğer dillerdeki genel türlerden farklı olarak, C++ şablonları değer parametreleri olarak da adlandırılan tür olmayan parametreleri destekler. Örneğin, standart kitaplıktaki std::array sınıfına benzer bir örnekte olduğu gibi bir dizinin uzunluğunu belirtmek için sabit bir tamsayı değeri sağlayabilirsiniz:
template<typename T, size_t L>
class MyArray
{
T arr[L];
public:
MyArray() { ... }
};
Şablon bildirimindeki söz dizimine dikkat edin. Değersize_t
, derleme zamanında şablon bağımsız değişkeni olarak geçirilir ve veya bir constexpr
ifade olmalıdırconst
. Bunu şu şekilde kullanırsınız:
MyArray<MyClass*, 10> arr;
İşaretçiler ve başvurular dahil olmak üzere diğer değer türleri türü olmayan parametreler olarak geçirilebilir. Örneğin, şablon kodu içindeki bir işlemi özelleştirmek için bir işleve veya işlev nesnesine işaretçi geçirebilirsiniz.
Tür olmayan şablon parametreleri için tür kesintisi
Visual Studio 2017 ve sonraki sürümlerde ve mod veya sonraki sürümlerde /std:c++17
, derleyici ile auto
bildirilen tür olmayan bir şablon bağımsız değişkeninin türünü gösterir:
template <auto x> constexpr auto constant = x;
auto v1 = constant<5>; // v1 == 5, decltype(v1) is int
auto v2 = constant<true>; // v2 == true, decltype(v2) is bool
auto v3 = constant<'a'>; // v3 == 'a', decltype(v3) is char
Şablon parametresi olarak şablonlar
Şablon bir şablon parametresi olabilir. Bu örnekte, MyClass2'nin iki şablon parametresi vardır: tür adı parametresi T ve şablon parametresi Arr:
template<typename T, template<typename U, int I> class Arr>
class MyClass2
{
T t; //OK
Arr<T, 10> a;
U u; //Error. U not in scope
};
Arr parametresinin gövdesi olmadığından parametre adları gerekli değildir. Aslında, gövdesinden Arr'ın tür adına veya sınıf parametresi adlarına başvurmak bir hatadırMyClass2
. Bu nedenle, bu örnekte gösterildiği gibi Arr'ın tür parametre adları atlanabilir:
template<typename T, template<typename, int> class Arr>
class MyClass2
{
T t; //OK
Arr<T, 10> a;
};
Varsayılan şablon bağımsız değişkenleri
Sınıf ve işlev şablonları varsayılan bağımsız değişkenlere sahip olabilir. Bir şablonun varsayılan bağımsız değişkeni olduğunda, şablonu kullandığınızda belirtilmemiş olarak bırakabilirsiniz. Örneğin, std::vector şablonu ayırıcı için varsayılan bir bağımsız değişkene sahiptir:
template <class T, class Allocator = allocator<T>> class vector;
Çoğu durumda varsayılan std::allocator sınıfı kabul edilebilir olduğundan aşağıdaki gibi bir vektör kullanırsınız:
vector<int> myInts;
Ancak gerekirse aşağıdaki gibi bir özel ayırıcı belirtebilirsiniz:
vector<int, MyAllocator> ints;
Birden çok şablon bağımsız değişkeni için, ilk varsayılan bağımsız değişkenden sonraki tüm bağımsız değişkenlerin varsayılan bağımsız değişkenleri olmalıdır.
Parametreleri varsayılan olarak atanmış bir şablon kullanırken boş açılı ayraç kullanın:
template<typename A = int, typename B = double>
class Bar
{
//...
};
...
int main()
{
Bar<> bar; // use all default type arguments
}
Şablon uzmanlığı
Bazı durumlarda, bir şablonun herhangi bir tür için tam olarak aynı kodu tanımlaması mümkün veya istenen bir durum değildir. Örneğin, yalnızca tür bağımsız değişkeni bir işaretçi, std::wstring veya belirli bir temel sınıftan türetilmiş bir tür olduğunda yürütülecek bir kod yolu tanımlamak isteyebilirsiniz. Böyle durumlarda, şablonun bu tür için bir uzmanlığını tanımlayabilirsiniz. Kullanıcı bu türdeki şablonun örneğini oluşturduğunda, derleyici sınıfını oluşturmak için özelleştirmeyi kullanır ve diğer tüm türler için derleyici daha genel şablonu seçer. Tüm parametrelerin özelleştirilmiş olduğu uzmanlıklar tam uzmanlıklardır. Parametrelerin yalnızca bazıları özelleştirilmişse, kısmi özelleştirme olarak adlandırılır.
template <typename K, typename V>
class MyMap{/*...*/};
// partial specialization for string keys
template<typename V>
class MyMap<string, V> {/*...*/};
...
MyMap<int, MyClass> classes; // uses original template
MyMap<string, MyClass> classes2; // uses the partial specialization
Her özel tür parametresi benzersiz olduğu sürece bir şablonda herhangi bir sayıda uzmanlık bulunabilir. Yalnızca sınıf şablonları kısmen özelleştirilebilir. Bir şablonun tüm tam ve kısmi uzmanlıkları özgün şablonla aynı ad alanında bildirilmelidir.
Daha fazla bilgi için bkz . Şablon Özelleştirmesi.
Geri Bildirim
https://aka.ms/ContentUserFeedback.
Çok yakında: 2024 boyunca, içerik için geri bildirim mekanizması olarak GitHub Sorunları’nı kullanımdan kaldıracak ve yeni bir geri bildirim sistemiyle değiştireceğiz. Daha fazla bilgi için bkz.Gönderin ve geri bildirimi görüntüleyin