Haftalık C++ 34 – Kullanıcı Tanımlı Değişmezler (“User-defined literals”)

Merhaba yazılımperver dostlarım, modern C++ yazılarımıza devam ediyoruz. C++ 11’den kalan bir kaç kabiliyetten biri olan Kullanıcı Tanımlı Değişmezlere (“user-defined literals”) göz atacağız.

Kullanıcı tanımlı olmayan değişmezler aslında C++ 11’den önce de dilde bulunuyordu (“built-in type” olarak nitelenebilir). Örneğin:

  • 13 (10 luk düzende 12), 010 (8 lik düzende 8), 0x13 (16’lık düzende 19) olarak tam sayıları,
  • 3.14, 2e1, kayan noktalı sayılar,
  • ‘a’, ‘\t’, “deneme”, karakter ve metinler,

Yukarıdakilerin yanında, sonuna eklendikleri sayıların tipini ifade eden ekler de mevcut. Şöyle ki:

  • 16U, unsigned int
  • 010L, long
  • 3.14F, float
  • 0x12ULL, unsigned long long

İşte C++ 11, bunların yanında kendi değişmezlerimizi de tanımlamamıza imkan sağlama olanağı sunuyor. Burada, elbette bu belirli kaidelere göre yapılmaktadır ki “User-defined literals sayfasında detaylı bir şekilde anlatılmaktadır ama öncesinde bu mekanizma ile kodlarımız içerisinde neler yapabileceğimize ilişkin örneklere bakalım 😉

  • Tam sayı değişmezlerine örneğin _km/_cm ekleyebiliriz. Ör. 12_km, 126_cm.
  • Ya da kayan sayı değişmezleri ile de bunları kullanabiliriz. Ör. 123.32_km
  • Metinlerle de kullanılabiliyor. Ör. “Merhaba”_str gibi kullanılabilir.

Örneklere baktığınız zaman, kullanıcı tanımlı değişmezlerin izlemesi gereken format hakkında bir fikriniz olduğunu düşünüyorum. Şöyle ki:

<“Built_in-Literal”>_<“Suffix”>

Formatı gördük peki bunları nasıl tanımlayabiliriz. Bu tanımlamalar, genel olarak değişmez operatörü (“literal operator”) olarak isimlendiriliyor. Hemen bakalım nasıl tanımlayabileceğimize:

<DönüşTipi> operator “” <SonEk> (<Parametreler>)

Şimdi uzunluklar için bunun bir kullanımına bakalım:

Örnekte de görebileceğiniz üzere birimler arası dönüşümleri bu mekanizma sayesinde çözmüş olduk. Tabi bunu, farklı şekillerde de halledebilirdik ama bu şekilde hem de daha okunabilir hem de tip güvenli bir kullanım elde etmiş olduk.

Burada operatörleri tanımlarken dikkat etmeniz gereken bir husus da, ilgili değişmez operatörlerinde sadece şu tipleri kullanabiliyoruz:

  • unsigned long long int,
  • long double,
  • char,
  • wchar_t,  
  • char16_t,
  • char32_t,
  • const char *,
  • (const char * , std::size_t),
  • (const wchar_t * , std::size_t),
  • (const char16_t * , std::size_t),
  • (const char32_t * , std::size_t).

Şimdi yukarıdaki örneği performans anlamında bir adım daha öteye götürebiliriz. Nasıl mı? constexpr’ları kullanarak. Bu sayede, dönüşümleri derleme zamanında hesaplanmasını sağlayabileceğiz. Nasıl yapacağız? Aşağıdaki gibi 😉

C++ bir takım hazır değişmezler de sunuyor. Bunlar ve hangi C++ standardı ile sunulduklarına aşağıdaki tablodan görebilirsiniz:

std::literals::complex_literalsisim uzayı içerisinde tanımlı değişmezler
std::complex literal representing pure imaginary number
(function)
std::literals::chrono_literalsisim uzayı içerisinde tanımlı değişmezler
(C++14)
std::chrono::duration, saati ifade eder
(function)
std::chrono::duration, dakikayı ifade eder
(function)
(C++14)
std::chrono::duration, saniyeyi ifade eder
(function)
std::chrono::duration, mili saniyeyi ifade eder
(function)
std::chrono::duration, mikrosaniyeyi ifade eder
(function)
std::chrono::duration, nano saniyeyi ifade eder
(function)
(C++20)
std::chrono::year, yılı ifade eder
(function)
(C++20)
std::chrono::day, ayın gününü ifade eder
(function)
std::literals::string_literalsisim uzayı içerisinde tanımlı değişmezler
(C++14)
Karakter dizisini basic_stringtipine dönüştürür
(function)
std::literals::string_view_literalsisim uzayı içerisinde tanımlı değişmezler
Karakter dizisine ilişkin string view oluşturur
(function)

 

Özet olarak, bu mekanizma, tip güvenli (type safety) aritmetiksel işlemler ile daha emniyetli ve okunabilir kodlar yazmamıza yardımcı oluyor. Örneğin, bir kullanıcı tanımlı değişmez operatörünü bulamaz ise derleme hatası ile karşılaşabilirsiniz. Elbette, diğer bütün C++ özellikleri gibi çok dikkatli kullanmanız gerekiyor, aksi halde başınıza dert açabilir.

Kaynaklar kısmında verdiğim https://www.modernescpp.com/index.php/user-defined-literals sayfasında da güzel ve kapsamlı bir örnek var. O da mesafe birimlerini kullanıyor ama biraz daha farklı bir yaklaşımlar. Daha detaylı bir kullanım görmek isteyenler bu örneğe de göz atabilirler.

Evet dostlar, bir C++ 11 özelliğine daha birlikte bakmış olduk. Artık C++ 11 kabiliyetlerini bitirmeye oldukça yaklaştık. Bir sonraki yazımda görüşmek dileğiyle, kendinize iyi bakın sağlıkla kalın.

Kaynaklar

Bir cevap yazın

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

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.