Evet sevgili yazılımperver dostlarım, C++ 17 yenilikleri ile devam ediyoruz. Bu yazımda da bunlardan bir kısmına daha değiniyor olacağız.
İçerik
İsim Uzayları ve Enumerasyonlar için Öznitelikler
C++ 11 ile birlike bir takım öznitelikler dile eklenmişti, C++ 17 ile birlikte yeni öznitelikler ve kullanımları da eklenmiş durumda. Bu yazıda, bu özniteliklerin detaylarına girmeyeceğiz, neden? Çünkü bunlara zaten değindik, merak edenler için aşağıdaki yazıya bakmasını rica ediyorum:
Haftalık C++ 30 – Nitelikler (“attributes”)
Bu başlıkta ise C++ 17 ile gelen bu özniteliklerin kullanımlarına ilişkin bir kaç hususa değineceğim.
Bunlardan ilki, bu özniteliklerin, alan uzayları ile de birlikte kullanımı. Diyelim, kütüphane geliştiriyorsunuz ve artık kullanılmasını istemediğiniz API’leri bir adres uzayı içerisinde toplayarak gruplandırmak isterseniz bu artık mümkün olacak. Şöyle ki:
1 2 3 4 5 |
namespace [[deprecated]] APIv1 { void API(); } APIv1::API(); // Derleyici uyari verir |
Bunlardan bir diğeri ise, bu özniteliklerin, enumeratörler için de kullanılabilmesidir. Yine hemen bir örneğe bakalım:
1 2 3 4 5 |
enum class Sehirler { Ankara = 0, Van = 1, Gaziantep = 2, Antep [[deprecated]] = Gaziantep, }; |
Yukarıdaki tanımlamada Gaziantep ve Antep aynı numerik değeri ifade etse de, Antep kullanılması durumunda, derleyici uyarı verir.
Bu kabiliyete ilişkin detaylar için N4196 önerisine bakabilirsiniz.
“Uniform Initialization” Yenilikleri
C++ 11 ile birlikte “uniform intialization”‘ın sunulduğu ve bu sayede ilklendirme işlevlerinin nasıl ortaklandığından önceki yazılarımda bahsetmiştim. C++ 11 öncesinde, değişkenlerin ilklendirilmesi için aşağıdaki tanımlamalar kullanabiliyorduk:
1 2 3 4 5 6 7 |
Varsayılan İlklendirme ("default initialization"): std::string s; Değer İlklendirme ("value initialization") : std::string s{}; Direk İlklendirme ("direct initialization") : std::string s("demo"); Kopya İlklendirme ("copy initialization") : std::string s = "demo"; Liste İlklendirme ("list initialization") : std::string s{'d', 'e', 'm', 'o'}; Toplu İlklendirme ("aggregate initialization") : char s[5] = {'d', 'e', 'm', 'o'}; Referans İlklendirme ("reference initialization"): char& c = s[0]; |
C++ 11 ile birlikte, bu tanımlamaları ikiye indirebildik (yukarıdaki ilklendirmeler halen geçerli tabi). Şöyle ki:
1 2 |
Direk Liste İlklendirme ("direct list initialization"): T object {arg1, arg2, ...}; Değer Liste İlklendirme ("copy list initialization") : T object = {arg1, arg2, ...}; |
Fakat, bu kullanım bir takım sıkıntılara yol açabiliyordu. Özellikle auto tanımlamalarında.
Öncelikle, auto ile kullanım durumlarında, tipin kendisi yerine yine std::initializer_list tipi çıkarımında bulunuluyordu. Yani, aşağıdaki tanımlamaların hepsi için çıkarılan tip std::initializer_list<int>‘di.
1 2 3 4 |
auto a = {42}; // std::initializer_list<int> auto b {42}; // std::initializer_list<int> auto c = {1, 2}; // std::initializer_list<int> auto d {1, 2}; // std::initializer_list<int>. Dikkat: -fpermissive ile derlemek gerekebilir |
Bu durumların yanında, auto dönüş tipine sahip fonksiyonlar için de benzer bir problem olmakta. Bu durumların önüne geçmek için, C++ 17 ile birlikte iki yeni kural tanımlandı:
- Birden fazla değer içeren {} ilklendirmeleri, auto değişkenler için “ill-formed”, hatalı, kabul edilecek (yukarıdaki dördüncü satır),
- {} içerisinde tek bir eleman var ise bu, auto değişken için çıkarım olarak std::initializer_list yerine bu elemanın tipi kullanılacak, çoklu eleman durumunda ise eskisi gibi davranacak. Yani, yukarıdaki tanımlamalar için, C++ 17 ile birlikte, çıkarımda bulunan tipler aşağıdaki gibi olacak:
1 2 3 4 |
auto a = {42}; // std::initializer_list<int> auto b {42}; // int auto c = {1, 2}; // std::initializer_list<int> auto d {1, 2}; // hata |
Detaylar için N3922 sayfasına göz atabilirsiniz.
Enumerasyon İlklendirme
C++ 11 ile birlikte gelen enumerasyon sınıflar, normalde tanımlandıkları temel tipler ile ilklendirilememekteydiler. C++ 17 ile bu mümkün artık:
1 2 3 4 5 6 |
enum class Handle : uint32_t { Valid = 0, NotValid = 1 }; Handle h { 42 }; // C++ 17 öncesi derleme hatası, sonrası için uygun |
Bu ve benzeri kullanımlar için https://www.nextptr.com/tutorial/ta1425731095/typesafe-integer-types-with-list-initialization-of-scoped-enums sayfasına da göz atabilirsiniz.
Kaldırılan Özellikler
C++ 17 ile birlikte bir takım özellikler de artık dilden çıkarılmış durumda. Bunların detaylarına çok girmeyeceğim, keza artık yoklar 🙂 Elbette merak edenler için ilgili bağlantıları ekliyor olacağım. Şimdi bu kabiliyetlere bakalım:
- operator++(bool) her ne kadar çok önceleri “deprecated” olarak işaretlense de, dilde bulunmaktaydı. C++ 17 ile birlikte silinmiş durumda
- “trigraph”‘lar da dilden çıkarılmış durumda (şu ana kadar hiç kullanmadım, merak edenler şu sayfaya göz atabilirler: https://www.geeksforgeeks.org/trigraphs-in-c-with-examples/
- register anahtar kelimesi çıkarılmış durumda (bir takım derleyiciler uyarı vererek kodu derlese de, dilden çıkarılmış durumda)
- Dinamik istisna tanımlamaları çıkarılmış durumda, buna ilişkin detaylar için de https://en.cppreference.com/w/cpp/language/except_spec
- std::auto_ptr, C++ 11 ile eklenmiş bu kabiliyet, C++ 17 ile çıkarılmış durumda. std::unique_ptr ve taşıma semantiği ile bu kabiliyetin çok bir anlamı kalmıyor. Buna ilişkin açıklamayı da Herb Sutter şu yazısında güzel anlatıyor: https://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/
- std::random_shuffle API’leri çıkarılmış durumdadır. Bunun arkasında yatan motivasyona da https://meetingcpp.com/blog/items/stdrandom_shuffle-is-deprecated.html sayfasından göz atabilirsiniz.
Evet sevgili dostlar bir yazımızın daha sonuna gelmiş bulunuyoruz. C++ 17’nin de bir çok kabiliyetini işlemiş olduk. Bundan sonra artık, C++ 20’ye ilişkin kabiliyetlere ya da örnek kullanımlara eğiliyor olacağız. Bir sonraki yazıma bol kodlu günler diliyorum 🙂