C++17 - templates

C++17 standartlarıyla beraber şablon ifadelerinde de önemli seviyede değişiklikler
oldu.Deyimlerdeki(statement) sentaks ağırlığı giderek hafiflese de bana kalırsa
dili öğrenmek isteyen genç arkadaşlar için biraz daha çabalayacakları bir hale
geliyor.

Katlı ifadeler (Fold expressions)

Hatırlarsınız değişken parametreli şablon fonksiyonların özyinelemeli yaklaşarak
yazımını yazmıştım.

C++17 ile beraber bu yaklaşım da daha da kolaylaşarak senktaks olarak geliştiriciyi
rahatlatıyor. Örneğin,

template<typename T>
void println(T v)
{
cout << v << endl;
}

template<typename T, typename... Types>
void println(T first, Types... values)
{
println(first);
println(values...);
}

daha önce yazdığımız println fonksiyonu katlı ifadeler ile şu hale geliyor.

template<typename ...Args>
void Println(Args ...args)
{
((cout << args << '\n'), ...);
}

Bu arada katlı ifadelerin açılımı
ise şu şekilde oluyor;

( pack op ... ) 	(1) 	
( ... op pack ) (2)
( pack op ... op init ) (3)
( init op ... op pack ) (4)

Şablon sınıflarında argüman türü tespiti (template deduction type)

Şablon sınıflarda argüman türü tespiti derleyici tarafından yapılıyordu zaten.
Fakat sınıflar için aynı tespit sözkonusu değildi. C++17 ile beraber artık
derleyiciler bu konuda da kodu sadeleştiriyor. Şöyle ki;

std::pair<int, std::string> p(34, "C++ İstanbul"s);

auto p2 = make_pair(34, "C++ İstanbul"s);

std::pair p3(34, "C++ İstanbul"s);

İlk ifadede görüldüğü gibi ‘p’ değişkeni tanımlanırken türlerin verilmesi zorunlu.
Bu sentaks kalabalığından az çok kurtulmak isteyen ‘make_pair’ fonksiyonunu
kullanarak şablon fonksiyonlardaki türlerin tespiti özelliğinden
faydalanabiliyordu. C++17 ile beraber ise artık şablon sınıfları da tür tespitini
otomatik yapabildiğinden sentaks iyice sadeleşmiş oluyor.

Kullanıcı tanımlı şablon türü tespiti (user defined template deduction)

C++17 ile beraber gelen otomatik argüman türü tespitine kullanıcının da müdahil
olması sağlanmış. Belki de bu dil bu yüzden bu kadar çok seviliyor :).

explicit(optional) template-name ( parameter-declaration-clause ) -> simple-template-id ;

şeklinde bir sentaks ile argüman türü tespiti yapılırken derleyiciye direktif
verebiliyoruz.

Örneğin aşağıdaki gibi bir durumda,

template<typename T>
struct MyString
{
T t;
};

MyString(const char *) -> MyString<std::string>;

MyString mystr{"A String"};

görüldüğü üzere MyString sınıfı için const char * türü şablon argümanı olarak
geçildiğinde direktif olarak tür tespitinin std::string olarak yapılmasını
istiyoruz. Aslında genel olarak Şablon sınıflarında argüman türü tespiti
konusunda bahsettiğimiz tür tespiti de aynı şekilde yapılıyor.

template<class T>
std::optional(T) -> std::optional<T>;

gibi.

if constexpr

Devam etmeden önce hatırlarsanız C++11 standartlarıyla beraber gelen ‘constexpr’
anahtar sözcüğü ile derleme zamanında sabit değerli ifadeler tanımlayabiliyorduk.
if constexpr ise derleme zamanında koşul kontrolü yapabilmemizi sağlar.
Type traits konusunda std::enable_if ten bahsetmiştik aslında kısaca SFINAE
temelli derleme zamanı için yazılmış bu tarz kodların sadeleştirilmesini sağlar.

template <class T, typename = typename enable_if<is_integral<T>::value, T>::type>
void println(T a)
{
cout << "if T is a integral type: " << a << endl;
};


template <class T>
void println(T a)
{
if constexpr (std::is_integral_v<T>)
cout << "if T is a integral type: " << a << endl;
}

Ne kadar basit bir özellik gibi gözükse de derleme zamanını seven C++
geliştiricileri oldukça büyük bir etkiye sahip bir özellik.

Sabit şablon parametreleri için auto

Generic lambdalardan sonra auto anahtar sözcüğünü şablon sınıfları için sabit
parametreler için de kullanabileceğiz. Aslında yine bir nevi kod daha okunabilir
hale gelirken sadeleşiyor.

template <auto size>
using myIntArray = std::array<int, size>;

veya static constexpr’lerde kullanımında da ciddi sadeleştirme sağlıyor.


//C++14

template <typename T, T value>
constexpr T TConst = value;

constexpr auto const MyConst = TConst<int, 100>;

//C++17
template <auto value>
constexpr auto TConst = value;

constexpr auto const MyConst = TConst<100>;

gibi.