> 'constexpr' anahtar sözcüğü : >> 'Constant Expressions' : Derleme zamanında derleyicilerin, ilgili ifadelerin değerini net olarak hesaplayabildiği ifadelerdir. Bir diğer deyişle bir sabit ifadesi kullanmakla bu ifadeyi kullanmak arasında bir farklılık yoktur. >>> Örneğin C ve C++ dillerinde 'sizeof()' operatörü bir 'constant expression' dur. >>> C dilinde şu şekilde yapılan bir 'initialize' aslında 'constant expression' değildir fakat C++ dilinde 'constant expression' => "const int x = 100;". >>> Buradaki kilit nokta, eşitliğin sağ tarafında bir 'constant expression' olmasıdır. Fonksiyonların geri dönüş değeri kullanıldığında, 'x' değişkeni 'constant expression' olmaktan çıkar. * Örnek 1, // Some code here... int foo(); int main() { const int x = foo(); // 'x' is a 'const' variable. const int y = 100; // 'y' is a 'const' variable, but the expression is a 'constant expression'. } >> C++ dilinde de bu anahtar sözcük ile tanımlanan nesnelere ilk değer vermek zorunludur. Ayrıca ilk değeri veren ifade de 'constant expression' olmak zorundadır. 'const' anahtar sözcüğünde ilk değer veren ifade olarak böyle bir zorunluluk yoktur. Artık bu anahtar sözcük ile tanımlanan değişkenleri, 'constant expression' gereken her yerde kullanabilirim. * Örnek 1, // Some code here... int foo(); int main() { constexpr int x = 100; // Bir 'constant expression' gereken her yerde kullabilirim. const int y = foo(); // Bir 'constant expression' gereken her yerde kullanamam. } >> Bu anahtar sözcük aslında değişkenin türünü nitelemez. Sadece ilgili ifadenin, 'Constant Expression' yerine kullanılabileceğini söylemektedir. * Örnek 1, // Some code here... int main() { constexpr int x = 100; // 'x' değişkeninin türü 'const int'. decltype(x) y; // İlk değer verilmediğinden dolayı sentaks hatasıdır. } * Örnek 2, // Some code here... int foo(); int main() { const int x = foo(); const int y = 1000; // Bir 'constant expression'. constexpr int a = 10; // Bir 'constant expression'. constexpr int b = 20; // Bir 'constant expression'. constexpr int c = a + b; // Bir 'constant expression'. constexpr int d = a + y; // Bir 'constant expression'. constexpr int e = x + a; // Bir 'constant expression' değil. Dolayısıyla bu çağrı bir sentaks hatasıdır. Çünkü derleme zamanında // değeri hesaplanamıyor. } * Örnek 3, // Some code here... int g = 10; int main() { // Buradaki 'const' anahtar sözcüğü aslında fazlalık. Çünkü ilgili 'constexpr' ifadesi 'p1' değişkenini // örtülü olarak 'const' yapmaktadır. Yani 'p1' artık başka bir nesneyi GÖSTEREMEZ. // int* const p1 = &g; constexpr int* const p1 = &g; // Buradaki 'const' anahtar sözcüğü ise 'p2' tarafından gösterilen o nesnenin 'const' olduğunu belirtir. // 'constexpr' de yine 'p2'nin 'const' olduğunu belirtmektedir. // const int* const p2 = &g; constexpr const int* p2 = &g; } >> 'constexpr functions' : Fonksiyonların imzalarını yazarken, geri dönüş değerinin türünü yazmadan evvel, 'constexpr' anahtar sözcüğünü kullanmamız bu fonksiyonu 'constexpr function' yapar. Eğer bu tip fonksiyonlara da argüman olarak 'constant expression' değişkenler geçilirse, bu fonksiyonun geri dönüş değeri DERLEME ZAMANINDA hesaplanır. * Örnek 1, // Some code here... constexpr int sum_square(int a, int b) { return a*a + b*b; } int main() { sum_square(10, 20); // 'sum_square' fonksiyonu bir 'constexpr function' dur. // 'sum_square' fonksiyonuna geçilen her bir parametre bir 'constant expression' dur. Yani derleyici bu // ifade yerine bir 'sabit' (500) kullanacak. constexpr int x = sum_square(10, 20); // 'x' in değeri '500'. int a = 10; int b = 20; ++a; --b; sum_square(a, b); // Sentaks hatası değildir fakat normal bir fonksiyon çağrısıdır. Geri dönüş değeri artık ÇALIŞMA ZAMANINDA // elde edilecek. Dolayısıyla bu ifade bir 'constant expression' DEĞİL. constexpr int c = sum_square(a, b); // Sentaks hatası. // 'constexpr' ANAHTAR SÖZCÜĞÜ İLE NİTELENEN ŞEYLER DERLEME ZAMANINA İLİŞKİN. } * Örnek 2, // Some code here... constexpr int sum_square(int a, int b) { return a*a + b*b; } constexpr int ndigit(int n) { if (n == 0) return 1; int digit_count = 0; while(n) { ++digit_count; val /= 10; } return digit_count; } constexpr int factorial(int n) { return n < 2 ? 1 : n * factorial(n-1); } constexpr bool isPrime(int val) { if(val == 0 || val == 1) return false; if(val % 2 == 0) return val == 2; if(val % 3 == 0) return val == 3; if(val % 5 == 0) return val == 5; for(int k = 7; k * k <= val; k += 2) if(val % k == 0) return false; return true; } int foo() { return 123; } int func() { return 321; } int main() { const int x = 198; // 'x' de bir 'constant expression' çünkü ilk değer aldığı ifade bir 'constant expression'. const int y = 3145; // 'y' de bir 'constant expression' çünkü ilk değer aldığı ifade bir 'constant expression'. constexpr int resultOne = sum_square(x, y); // Dolayısıyla fonksiyona gönderilen değişkenler birer 'constant expression'. İş bu sebepten dolayı // yukarıdaki bu ifade, COMPILE TIME açısından bir sabit. Yani değeri derleme zamanında // hesaplanmıştır(~9milyon). constexpr int resultTwo = ndigit(sum_square(x, y)); // 'sum_square' fonksiyonu bir 'constant expression' olduğundan dolayı, 'ndigit' fonksiyonu da bir // 'constant expression' olmuştur. Yani bunun da değeri DERLEME ZAMANINDA hesaplanacak. // (7) constexpr int resultThree = factorial(ndigit(sum_square(x, y))); // 'factorial' fonksiyonunun parametresi 'constant expression' olduğundan, işbu fonksiyon da bir // 'constant expression' olur. Değeri DERLEME ZAMANINDA hesaplanır. // (5040) // AŞAĞIDAKİ AÇIKLAMAYI DİKKATE ALINIZ: /* " factorial(ndigit(sum_square(x, y))); " Yukarıdaki ifadedeki 'x' ve 'y' değişkenleri birer 'constant expression' değiller ise hesapalama ÇALIŞMA ZAMANINDA; aksi halde DERLEME ZAMANINDA hesaplanır. Dolayısıyla fonksiyonları 'constexpr' olarak bildirmek/tanımlamak işimize yarayabilir. */ constexpr bool val = isPrime(factorial(ndigit(sum_square(x, y))) + 1); // Compile Time // 'val' değişkeninin değeri DERLEME ZAMANINDA hesaplanmıştır. Çünkü bütün fonksiyonlar 'constexpr' olarak // nitelendirilmiş ve geçilen parametreler de 'Constant Expression' şeklinde. const bool valueTwo = isPrime(factorial(ndigit(sum_square(x, y))) + 1); // 'valueTwo' değişkeninin değeri DERLEME ZAMANINDA hesaplanmıştır. bool valueThree = isPrime(factorial(ndigit(sum_square(foo(), func())))); // 'valueThree' değişkeninin değeri ÇALIŞMA ZAMANINDA hesaplanmıştır. } >>> NEDEN HER BİR FONKSİYON 'constexpr function' OLAMAZ? ÇÜNKÜ, >>>> Bu tip fonksiyon olabilmeleri için almış oldukları parametreler ve geri döndürdükleri değerler birer 'literal type' olmalı. >>>> Bu tip fonksiyon olabilmeleri için bloklarında 'static' yerel değişkenler kullanılmamalı. Çünkü bu tip fonksiyonlar, DERLEME ZAMANINDA işlem yapmaktalar. >>> Normal şartlarda derleyiciler, 'constexpr' olmayan bir fonksiyonun koduna DERLEME ZAMANINDA bakmazlar. Sadece 'linker' isimli yardımcı program, '.exe' dosyasını üretebilmek için, çağrılan fonksiyonun imzası ile gövdesini eşlemek için ilgili fonksiyonun gövdesine bakması gerekmektedir. Aksi durumda kodumuz derlenir fakat çalıştırılamaz. Fakat 'constexpr' fonksiyonlar içim durum tam tersidir. Derleyicilerin, 'constexpr' fonksiyonların gövdelerine bakmaları gerekmektedir ki DERLEME ZAMANINDA ilgili fonksiyon bir çıktı üretsin. Bundan sebeptir ki 'constexpre functions' ların tanımlamarı 'header files' içerisinde olmalı. Bu da implementasyonu ifşa etmektedir.