C++11'de, yazılan programların her zamankinden daha hızlı çalışmasına olanak tanıyan bir çok özellik bulunmaktadır. Bu özelliklerden biri de genelleştirilmiş sabit ifadeler (Generalized Constant Expressions), yani yazılan programların bazı parçalarının derleme zamanında hesaplamasından yararlanılmasını sağlamaktır. Sabit ifadelerin temel fikri, belirli hesaplamaları program çalıştırıldığında değil de derleme zamanına havale etmektir. Bu yöntem, görünür bir performans avantajına sahiptir: Programın her çalıştırıldığında bazı hesaplamaların tekrar tekrar hesaplanmasına gerek kalmadan bir sefer yapıp işlem maliyetini O(1) düzeyine çekmektir. Kuralı tek bir cümleyle ifade etmek gerekirse: Derleme işlemi sırasında bir şey yapılabiliyorsa, onu derleme zamanına havale et bitsin. Örneğin bir sayının sinüs veya kosinüs değerini hesaplamanız mı gerekiyor? Bunu çalışma zamanına havale etmeden derleme zamanında bunu hesaplayan bir fonksiyon oluşturarak halletmek performans artışı demektir. Son olarak genelleştirilmiş sabit ifadeleri constexpr anahtar kelimesi kullanılarak oluşturulur.
|
Genelleştirilmiş sabit ifadelere ait bir fonksiyon örneği |
Genelleştirilmiş sabit ifadelere ait bir fonksiyon içerisinde dikkat edilmesi gereken kısıtlamalardan biri constexpr bir fonksiyon sadece constexpr fonksiyon çağrısında bulunabilir. Recursive bir çağrı kısıtlaması yoktur. Aşağıda örnek bir uygulama görülebilir:
|
Recursive genelleştirilmiş sabit ifadelere ait bir fonksiyon örneği |
Dizi tanımlaması yapılırken bir hesap yapılması gerektiğinde klasik fonksiyon çağrısı yapılamamakta (derleme zamanında dizinin boyutunun bilinmesi gerektiğinden) ve makrolar kullanılmaktadır. C++'ın makrolarla arası iyi olmadığını da bir kenara koyarsak bu noktada makroları devre dışı bırakıp yerine genelleştirilmiş sabit ifadeleri kullanılabilir. Aşağıda buna ilişkin bir örneği inceleyebilirsiniz:
|
Makro yerine genelleştirilmiş sabit ifadelere ait bir fonksiyon örneği |
Genelleştirilmiş sabit ifadelerine ilişkin kullanım senaryolarından biri de nesneleri compile time sırasında kullanımına ilişkindir. Aşağıda genelleştirilmiş sabit ifadeleri kavramının olmadığı bir örneği görebiliriz:
|
Genelleştirilmiş sabit ifadeler ile Compile Time'da nesne kullanımı örneği -1 |
Peki nu noktada ben bir kare objesini derleme zamanında oluşturup alanını derleme zamanında hesaplamak istediğimde ne yapmam gerekir?
Birincisi constructor constexpr olmalı ve ikincisi çağıracağım fonksiyon constexpr olmalıdır.
|
Genelleştirilmiş sabit ifadeler ile Compile Time'da nesne kullanımı örneği -2 |
Constexpr değişkenler üzerindeki kısıtlamalar
- Constexpr gösterici değişkenlere de sabit ifadesi olma özelliğine sahip adreslerle ilk değer verilmelidir. Bu noktada şu bilinmelidir ki, yerel değişkenlerin adresleri sabit ifadesi olarak kabul edilmemekte fakat global değişkenlerin adresleri sabit ifadesi olarak kabul edilmektedir.
- Fonksiyonların parametre değişkenleri ve bir sınıfın static olmayan veri öğeleri constexpr olarak bildirilemezler.
- constexpr nesneye sabit ifadeleriyle ilk değer verilmesi zorunluyken const nesne için böyle bir zorunluluk yoktur.
Constexpr fonksiyonlar üzerindeki kısıtlamalar
- Tek return ifadesinden oluşmalıdır (birkaç istisna dışında)
- Yalnızca diğer constexpr fonksiyonlarını return ifadesi içinde çağırabilir.
- constexpr anahtar kelimesinin fonksiyon tanımlamasında kullanıldığında fonksiyonu otomatik olarak inline yapar (constexpr fonksiyonlar tipik olarak başlık dosyalarında tanımlanmalıdır).
Note:
- Derleyicinin derleme zamanında değerini bilme ya da hesaplama garantisi olan ifadelere sabit ifadesi denmektedir.
- constexpr ile tanıtılan bir değişkene bir sabit ifadesi ile ilk değer verilmeli ve derleyici bu kontrolü yapmakla yükümlüdür. constexpr bir değişkene ilk değer verilmemesi ya da sabit ifadesi olmayan bir ifade ile ilk değer verilmesi doğrudan kural hatasıdır.
- constexpr anahtar sözcüğü hem bir değişkenin hem de bir fonksiyonun tanımında kullanılabilmektedir.
- constexpr bir değişken ifadesi bir dizi tanımında boyut ifadesi olarak kullanılabilir. Bir numaralandırma (enumaration) değeri olarak kullanılabilir. Bir switch deyiminin case ifadesi olabilir. Sabit parametreli (nontype template parameter) bir şablonun açılımında arguman olarak kullanılabilir.