constexpr – 1

constexpr kabuk değiştirmiş C++’ın en önemli anahtar sözcüklerinden biri. Üç ayrı yazımı bu anahtar sözcüğe ayıracağım. Bu okumakta olduğunuz birinci yazım.

constexpr anahtar sözcüğü “constant expression” (sabit ifadesi) sözcüklerinden uydurulmuş. constexpr anahtar sözcüğüyle tanıtılan bir varlık kod içinde sabit ifadesi olarak kullanılabiliyor. Derleyicinin derleme zamanında değerlerini bilme ya da hesaplama garantisi olan ifadelere sabit ifadesi dendiğini hatırlayın. constexpr anahtar sözcüğü hem bir değişkenin hem de bir işlevin tanımında  kullanılabiliyor. constexpr anahtar sözcüğü ile tanımlanan işlevler ikinci yazımın konusu olacak.  Şimdilik yalnızca constexpr değişkenlerle  yetineceğim:

Yukarıdaki gibi bir bildirim  okuyucuya öncelikle şu bilgileri veriyor:
x değişkeni sabit ifadesi (constant expression) gereken her yerde kullanılabilir.
x, değeri hiç değişmeyecek bir değişken. Yani hayatta olduğu sürece hep aynı değerde kalacak. Bu açıdan bakıldığında constexpr anahtar sözcüğü const anahtar sözcüğünün anlamını da içeriyor.
x 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:
Şimdi gelelelim derleyicinin derleme zamanında yaptığı kontrollere:
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ü. constexpr bir değişkene ilk değer verilmemesi ya da sabit ifadesi olmayan bir ifade ile ilk değer verilmesi doğrudan sentaks hatası:
const anahtar sözcüğüyle tanıtılan değişkenlerin değerlerini değiştirmeye yönelik ifadelerin geçersiz olduğunu biliyorsunuz. constexpr değişkenler için de durum farklı değil:
Peki bu durumda const anahtar sözcüğü ile constexpr anahtar sözcüğü aynı anlama mı geliyor? Kesinlikle hayır. const anahtar sözcüğü ile tanımlanan bir değişkene bir sabit ifadesi ile ilk değer vermek zorunlu değil. Bir const değişken ancak bir sabit ifadesi ile ilk değerini aldığında sabit ifadesi olarak kullanılabiliyor. Ancak constexpr değişkenlere sabit ifadesi olmayan ifadeler ile ilk değer verilemiyor ve constexpr değişkenler her zaman sabit ifadesi olarak kullanılabiliyor. Kafanız mı karıştı?
Bir global değişken ya da bir yerel değişken constexpr anahtar sözcüğü ile tanıtılabilir. Bir sınıfın bir static veri öğesi constexpr olarak tanıtılabilir. Ancak işlevlerin parametre değişkenleri ve bir sınıfın static olmayan veri öğeleri constexpr olarak tanıtılamazlar:
constexpr anahtar sözcüğünü const anahtar sözcüğü ile birlikte kullanmak sentaks hatası olmasa da çoğu zaman gereksiz. Çünkü constexpr anahtar sözcüğü const anahtar sözüğünün anlamını da içeriyor:
Lakin constexpr değişkenimiz gösterdiği yer const olan (low level const) bir gösterici ise durum farklı. (Burada nedense lakin sözcüğünü kulanmak içimden geldi.) Önce const anahtar sözcüğüyle gösterici değişkenlerin tanımlanmasını ve bu konudaki terminolojiyi bir hatırlayalım:
Şimdi de aşağıdaki koda bakalım:
Burada p değişkeni constexpr olarak tanıtılan ve gösterdiği yer const olan bir gösterici. const anahtar sözcüğü kullanılmasaydı, tanımlama yine geçerli olurdu ancak tanımlamanın anlamı değişirdi.
Bu arada constexpr değişkenlere bir sabit ifadesi ile ilk değer verilmesi zorunlu olduğundan constexpr gösterici değişkenlere de sabit ifadesi olma özelliğine sahip adreslerle ilk değer verilmeli. Yerel değişkenlerin adresleri sabit ifadesi olarak kabul edilmiyor:

Necati Ergin

C ve Sistem Programcıları Derneğinde eğitmen olarak çalışıyor.

Bunlar da ilginizi çekebilir

constexpr – 1” için 10 yorum

  1. Selamlar,
    ————————————-
    int func();

    int main()
    {
    const int x1 = func(); //geçerli
    const int x2 = 10; //geçerli
    constexpr int cx1 = x1; //geçersiz. x1 sabit ifadesi değil
    constexpr int cx2 = x2; //geçerli, x2 sabit ifadesi
    constexpr int cx3 = func(); //geçersiz, func() sabit ifadesi değil

    int a[x1]; //geçersiz, dizi boyutu sabit ifadesi değil
    int b[x2]; //geçersiz, dizi boyutu sabit ifadesi.
    int c[cx3]; //geçerli, dizi boyutu sabit ifadesi.

    return 0;
    }
    ————————————-
    ifadesi içindeki int b[x2]; geçerli bir ifade olması gerekmiyor mu?

    1. Merhaba Kenan Bey,
      Geçerli yerine yanlışlıkla geçersiz yazılmış. Uyarı için teşekkür ederim. İyi çalışmalar.

  2. int x = 10;
    constexpr int *p1 = &g; //geçerli, &g sabit ifadesi.
    constexpr int *p2 = &x; //geçersiz, &x sabit ifadesi değil.

    std::cout << "*p2:" <<*p2 << std::endl;

    ifadesi VS2015 ile derlenip çalıştığı zaman ekrana *p2:10 yazmasının sebebi nedir Necati Hocam?

    1. Merhaba,
      p2 gösterici nesnesi x değişkenini gösterdiğine göre *p2 ifadesi x’in kendisi. Bu durumda ekrana p2’nin gösterdiği nesnenin değerini yani x’in değerini yazdırmış oluyoruz.

    2. Necati bey öncelikle tüm cevaplarınız için teşekkürler.
      Soruyu biraz kapalı sorduğum için yanlış anlaşıldı. Kusura bakmayın.
      /////////////////////////////////////////////
      int x = 10;
      constexpr int *p1 = &g; //geçerli, &g sabit ifadesi.
      constexpr int *p2 = &x; //geçersiz, &x sabit ifadesi değil.
      std::cout << "*p2:" <<*p2 << std::endl;
      /////////////////////////////////////////////
      constexpr int *p2 = &x; ifadesi geçersiz olduğundan dolayı derlenip çalışmaması gerekiyordu ama derlenebildi hatta link edilebilde ve çalıştı. constexpr int *p2 = &x; bu ifade geçersiz değil mi yoksa kaçırdığımız kısım ne acaba?

      Teşekkürler,
      İyi çalışmalar

      1. Haklısınız. Gösterdiğiniz kodun derlenmemesi gerekiyor. Yerel bir değişkenin adresi bir sabit ifadesi kabul edilmediğinden p2 gösterici değişkenine verilen ilk değer dilin kurallarını çiğniyor. Aklıma gelen olasılıklar
        i) x değişkenini global isim alanında tanımlamış olduğunuz için kod geçerli olabilir.
        ii) Derleyiciniz constexpr anahtar sözcüğünü implemente etmemiş ancak varlığını da etkisiz olarak değerlendirmiş olabilir.

    1. Evet. Yalnızca bir istisnai durum var. constexpr bir işlev söz konusu olduğunda (yakında bloğumuzda constexpr işlevlerle ilgili bir yazı yayımlanacak) işleve gönderilen değer sabit ifadesi değilse işlevin geri dönüş değeri çalışma zamanında hesaplanıyor. Eğer söz konusu işlev bir sabit ifadesi ile çağrılırsa işlevin geri dönüş değeri derleme zamanında hesaplanıyor. İlginiz için teşekkür ederim.

  3. Selamlar Necati Bey,

    the value of ‘cval’ is not usable in a constant expression hatası alırken

    kod hatasız bir şekilde çalışmaktadır. Burdaki kavramsal ayrımın sebebi nedir?

    1. Merhaba İbrahim Bey,

      Kod geçerli. Derleyicinizin sentaks hatası vermesi derleme için kullandığınız switch’ler ile ilgili olabilir. Ben cpp.sh de C++14 seçeneğiyle derleyip çalıştırdım:

      Gerçek sayı formatının farklı sistemlerde farklı olabilmesi nedeniyle derleyici kullanılan switch’lere bağlı olarak sentaks hatası vermiş olabilir diye düşünüyorum.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Kod Eklemek İçin Okuyun