C++ yazılarımıza devam ediyoruz. C++ 14 ile sunulan ve açıkçası benim daha önce hiç kullanmadığım (muhtemelen bir süre de kullanmayacağım) ama kabiliyetlerin bütünlüğü açısından değineceğim bir konu var, o da değişken şablonlar (Variable template). Bundan önceki yazılarımda “variadic templates” ‘a değinmiştim onlara da bir göz atmanızda fayda var (“variadic” ile “variable” terimlerini açık bir şekilde ifade edecek terim bulamadığımda, değişken olarak kullanacağım). Hemen buraya bir bağlantı ekliyorum:
Haftalık C++ 37 – Variadic Templates
Bu mekanizmalar, özellikle “template metaprogramming” yapıyorsanız işinizi kolaylaştıracaktır.
Açıkçası ben de buna göz attıktan sonra, özellikle performans kritik kabiliyetler için ihtiyaç duyabileceğiniz bir takım hesaplamaları derleme zamanında yapmanıza yardımcı olacak bir kabiliyet olduğunu düşünüyorum.
Şimdi gelelim kabiliyete, bu kabiliyeti , gördüğüm kadarıyla en güzel ve özet şekilde referans doküman sayfası anlatmış. Şöyle ki, değişken şablonlar, bir değişkenler ailesi ya da statik veri üyelerini tanımlamasını sağlıyor. Bu da nerede tanımlandığına göre değişiyor. Genel format aşağıdaki gibi oluyor:
template < parameter-list > variable-declaration
Eğer sınıf kapsamı dışında, isim uzayı dışında tanımlanırsa ise değişken ailesi tanımlar. Hemen örneğe bakalım.
1 2 |
template<class T> constexpr T pi = T(3.1415926535897932385L); // değişken şablonumuz |
yukarıdaki tanımlama ile bir pi değişken şablonu tanımlamış olduk. Peki bunun kullanımı nedir? Hemen ona da bakalım. Aşağıda da bunun kullanımına ilişkin örneği görüyoruz:
1 2 3 4 5 |
template<class T> T CalculateCircularArea(T r) // fonksiyon şablonu { return pi<T> * r * r; // pi<T> şablon değişkeninin kullanımı } |
bu örnekte de görebileceğiniz gibi, yukarıdaki tanımlama ile birlikte, pi değişkeni (daha doğrusu değişken şablon ailesi) farklı tipler için diğer şablonlarda kullanabiliyoruz. Şöyle ifade edelim. İlk yaptığımız, tanımlamada direk bir tip vermedik, fakat bu tipi hem int hem de double hem de benzeri tipler için diğer şablonar içerisinde kullanabilirsiniz. Yukarıdaki alan hesaplama da bunun bir örneği.
Fakat, diğer şablonlarda olduğu gibi, tanımlayacağınız her tip için derleyici bir tanımlama ekliyor olacak.
Eğer değişken şablon sınıf kapsamı içerisinde tanımlanırsa bu statik veri üyesi şablonu tanımlamaktadır. Hemen referans sayfasındaki örneğe bakalım:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using namespace std::literals; struct MatrixConstants { template<class T> using pauli = hermitian_matrix<T, 2>; // alias template template<class T> // Bu da statik üye örneği static constexpr pauli<T> sigmaX = { { 0, 1 }, { 1, 0 } }; template<class T> static constexpr pauli<T> sigmaY = { { 0, -1i }, { 1i, 0 } }; template<class T> static constexpr pauli<T> sigmaZ = { { 1, 0 }, { 0, -1 } }; }; |
yukarıdaki örnekte de aslında sınıf içerisinde kullanıma yönelik bir değişken tanımlıyoruz ve daha sonra, bu tanımlama ile statik veri üyeleri tanımlayabiliyoruz. Tabi bütün bunların derleme zamanında gerçekleştiğini sanırım hatırlatmama gerek yok.
Hala benimle misiniz? Şimdi biraz daha farklı bir örneğe bakalım :
1 2 3 4 5 6 7 8 9 |
template<typename T> T CompileTimeVariable = T(20); int main() { CompileTimeVariable <int> = 10; // Artık int tipindeki bu değişken 10 std::cout << CompileTimeVariable<int> << " "; // Çıktı: 10 std::cout << CompileTimeVariable<double> << " "; // Çıktı: 20.0 } |
Burada da, ilk pi örneğindeki kullanım yanında, değişken şablonlar ile, her bir tip icin değişkenin nasıl tanımlanabildiğine şahit oluyorsunuz.
Peki daha başka ne için bu kabiliyeti kullanabiliriz diye baktığınızda, “variadic template” ile çok ilginç ve faydalı kullanımlara şahit olabiliyoruz. Bunlardan birisi de, derleme zamanında trigonometrik çıktıların tabloda tutulması (eskiden ben de kaynak kritik bir kaç uygulamamda bu tabloları oluşturup kullanmıştım). İlgilenenleri aşağıdaki sayfaya alabiliriz:
https://accu.org/journals/overload/23/126/sommerlad_2087/
Hem referans sayfa da hem de diğer kaynaklarda da ifade edildiği üzere, C++ 14 öncesinde de burada sunuluna kabiliyetler bir şekilde sağlanabiliyordu (statik veriler ve constexpr fonksiyonlar) ama C++ 14 ile sunulan bu kabiliyet ile birlikte bu daha kolay ve okunabilir bir şekilde gerçekleştirebilmekte.
Bu kabiliyete, arkasındaki motivasyona ve daha detaylı örneklere göz atmak isterseniz http://isocpp.org/files/papers/N3651.pdf dokümanına bir göz atabilirsiniz.
Bir sonraki yazımda görüşmek dileğiyle kendinize iyi bakın, bol kodlu günler diliyorum.