[:tr]Haftalık C++ – 4 Yapısal Bağlama (“Structured Binding”)[:en]Weekly C++ – 4 Structured Binding[:]

[:tr]Merhabalar arkadaşlar, yeni bir haftalık C++ yazısı ile birlikteyiz. Bu yazımızda da modern C++ 17 ile birlikte gelen bir diğer kabiliyet olan “Structured Binding”‘e bakacağız. Ben yazımda buna kısaca “yapısal bağlama” diyeceğim.
Bu kabiliyet bize ne kazandırıyor? Kısaca bu kabiliyet ile birlikte birden fazla değişkenin tek bir ifade ile “tuple”/”pair” ya da benzeri yapıları kullanarak ilklendirebileceğiz, daha önce std::tuple ve benzeri yapılarla dolaylı yoldan sağlanan çoklu değer dönme kabiliyetini de artık kullanabileceğiz. Bu kabiliyetin arkasında yatan motivasyonun detayları için kaynaklar kısmında verdiğim standart dokümanına bir göz atmanızda fayda var.
Buna benzer kabiliyetleri başka diller açıp atama (“unpacking“), çoklu atama (“multiple assignment“) isimleri ile sunuyorlar. Ör. Pyhton da (x, y) = 10, 20 diyerekten tek bir satırda ilgili değişkenleri atayabiliyorsunuz.
İşte bu kabiliyet artık C++ ile de sunuluyor.
Yazımda detaylı olarak bu kabiliyeti tek tek anlatmaktansa genel yapısından bahsedip daha önceki yazılarımda olduğu gibi çeşitli örnekler üzerinden giderek sizlere aktarmayı planlıyorum.

Genel yapı

Yapısal bağlama genel olarak aşağıdaki format ile özetlenebilir:
auto [element1, element2, ….] = { pair, tuple, struct ya da dizi tanımlamaları }

Dikkat edilecek hususlar:

  • “element1, …, ” ‘de virgül ile ayrılan elemanların adeti ile atama operatörü sağındaki elemanların sayısı aynı olmalıdır,
  • Atama operatörünün sağında ise aşağıdakilerden birisi olabilir:
    • std:: pair ya da std::tuple
    • bir struct nesnesi. Struct nesnesi içerisindeki üyelerin hiçbirisi statik olmamalı. Bunların tanımlanma sırasına göre atama operatörünün solundaki elemanlar doldurulacak
  • Sabit boyutlu dizi
  • Yukarıdaki durumlardan birisi sağlanmadığı durumda derleme hatası ile karşılaşırsınız
  • Bu arada atamalar sırasında gereksiz kopyalamaları önlemek adına olabildiğince atama operatörünün solunda referans tiplerini kullanmaya özen göstermekte fayda var
  • Operatörün solunda auto, auto&, const auto, const auto& ve auto&& kullanımları mümkün.

std::tuple ile kullanımı

Yapısal bağlama’nın ilk kullanım örneği tuple‘lar ile alaklı olacak. Özellikle “pair” (bayadır mevcut) ya da “tuple” (C++ 11 ile birlikte geldi) benzeri yapılar ile uğraşıyor iseniz bunların barındırdığı değerlere erişme ihtiyacı duymuşsunuzdur. std::pair aslında map konteynerinin temel taşı diyebiliriz. Std::tuple da std::pair‘in aslında bir anlamda genelleştirilmiş hali. Normal şartlarda tuple ile ifade edilen bir değişkene ilişkin elemanları farklı değişkenlere atamak (ya da açıp kullanmak) için önceden takip edilen yöntem std::tie() metoduydu. Yeni gelen bu kabiliyet ile birlikte “auto [var1, var2, …] = tuple;” kullanımı ile bu değişkenlere erişim sağlanıyor. Hemen buna ilişkin bir kullanıma bakalım:

tuple kullanımındaki bir diğer sıkıntı ise std::tie() ile tuple‘daki elemanların referansını almak mümkün değil idi. Bunun için tek yol “std::get<2>(employee)” metodu. Yeni mekanizma ile artık bu da mümkün:

Buradaki kullanımların benzeri std::pair ve std::array için de geçerlidir.

struct ile kullanımı

std::tuple‘a benzer şekilde struct nesnelerinin de her bir elemanına bu mekanizma ile tek bir seferde ulaşabiliyoruz.

Bu kullanımların benzer şekilde struct dönen metotlarda da kullanabilirsiniz.

Diziler ile kullanımı

Yukarıda anlatılan kullanımlar ile birlikte yapısal bağlamaya geleneksel diziler ile de kullanabilirsiniz. Aşağıda bu kullanıma ilişki örneği görebilirsiniz.
Burada önemli olan ilgili dizinin boyutunun belli olması.

move semantiği ile kullanımı

Yapısal bağlama yukarıda bahsettiğim gibi move semantiği ile de kullanılabilmektedir. Aşağıda bu kullanıma ilişkin örnek kodu görebilirsiniz:

std::map konteyneri ile kullanımı

Bu mekanizmanın bir diğer kullanımı ise std::map konteynerinin elemanlarının üzerinde gezinme.

Kaynaklar

[:en]Hello everybody, we are together again with another weekly C++ post. In this post, we are going to take a look at a feature that provided with C++ 17, “Structured Binding”‘. So what does this feature provide us? Briefly, this feature let you assign or initialize multiple variables with tuple/pairor similar structs with one statement. It is now also possible to return multiple variables which were possible only via std::tuple like constructs. You may check out the references for more motivation behind this feature.

Similar capabilites are provided as Unpacking, Multiple Assignment in other programming languages. For instance, in Python you can assign two variables with a single (x, y) = 10, 20statement. And now this is also possible with C++.

In my post, instead of going through all details of this capability, I will try to give you some important usages of this capability with sample codes.

General syntax:

Structured binding can be summarized with following syntax:
auto [element1, element2, ….] = { pair, tuple, struct or array  }

Points to consider:

  • “element1, …, ” the number of elements seperated with comma should be same as the ones provided at the right side of assignment operator,
  • The element at the right side of assignment can be one of following:
    • std:: pair or std::tuple
    • A struct instance. All of the struct members should be non-static. The order of definition is important,
  • Fixed size arrays,
  • You may encounter with compilation error if one of above conditions is not met,
  • To prevent any unnecessary copy operation, reference types should be used at the left side of assignment operator as much as possible,
  • auto, auto&, const auto, const auto& and auto&& can be used at the left side of assignment operator.

Usage with std::tuple:

The first usage of structured binding will be about tuple’s. If you are using “std::pair” or “std::tuple” then you probably required to access the individual data. In fact, std::pair is an important part of std::map. Std::tuple is a more generalized version of std::pair. Traditionally (before C++ 17), the approach to access the individual elements of tuple and assign them to other variables is perfomed through std::tie() method. With structured binding, it is possible to use “auto [var1, var2, …] = tuple;” to access corresponding variables. Let us look at an example usage:

Another issue with tuple usage is that it is not possible to get reference of elements with std::tie() method. Only way to do so is to use “std::get<2>(employee)” method. With this capability, this is also possible:

Same usage is also possible for std::pair and std::array.

Usage with struct:

We can also access and assign each member of struct objects similar to std::tuple.

This can also be used with functions that return struct.

Usage with arrays:

The structured binding can also be used with traditional arrays. A sample code for this usage is provided below. It should be noted that the size of array should be matched.

Usage with move semantics:

As I mentioned above structured binding can also be used with move semantics. You can find a sample code that illustrate this usage:

Usage with std::map:

You can also use this mechanism with std::map container to traverse elements as illustrated below:

References:

[:]