Macro’s vs Variadic Templates – 1

Variadic fonksiyonlar istenilen sayıda değişken almaları sayesinde bir çok işi kolaylaştırmışlardır. C++11 den önce C de bu ihtiyaç “…” elipsis operatörü ve va_* makrolarıyla çözülüyordu. Fakat bu çözüm çalışma zamanında işlediğinden yanlış kullanım veya beklenmedik durumlarda çalışma zamanı hataları veya seg fault dahi alınabiliyordu.

Örneğin;

int a ;

printf("%s", a);

Bu kod örneği derleme zamanında (compile time) hata vermez. Fakat çalışma zamanında seg fault alırsınız. C++11 de bu problem variadic templatelerle çözülüyor. Üstelik derleme zamanında çözüldüğü için yanlış kullanım durumunda hemen müdahale edebiliyorsunuz.

Variadic templates

Basit bir önekle devam edelim;

#include <iostream>

using namespace std;

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

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

int main()
{
   println("islam", "cppistanbul", 1299); //1
   println(6, 1, 0, "c++UG", 5, 7, 1); //2
  
  return 0;
}

“typename… Types” şablon parametre paketi(template parameter pack), “Types… values” ise fonksiyon parametre paketi (function parameter pack) şeklinde adlandırılıyor. template parameter packteki Types aslında bir tür listesi. Örneğin “1” durumunda bu liste “const char *, const char *, integer” şeklindedir.Function parameter pack ise bir değer listesidir. Yine “1” durumunda bu liste “islam, cppistanbul, 1299” şeklindedir. Elipsis (…) operatörüyle de bu değerler ve türler açılır(expand). Burda dikkat ederseniz iki tane println fonksiyonu var, basitçe bir oveload aslında. Bu overload ile aslında kısmi bir rekürsiv çağrı yapıyoruz. Daha iyi anlaşılması için adım adım ilerleyelim.

1.iterasyon:

“1” durumunda println fonksiyonu 3 tür ie çağırılmış. Template argument deduction yaparak B deki overload çağrılacak ve:

void println(T, Types ...) [with T = const char*; Types = {const char*, int}]

parametre bu şekilde belirlenecek. Derleyici bir tane yukarıdaki imzaya sahip bir fonksiyon oluşturacak. Ve dikkat edin A durumundaki tek parametreli template de şu şekilde derleyici tarafından yazılacak:

void println(T) [with T = const char*]

2. iterasyon:

B template fonksiyonu:

void println(T, Types ...) [with T = const char*; Types = {int}] 

şeklinde, A template fonksiyonu ise yine aynı imzaya sahip olacağından tekrar yazılmayacak.

3. iterasyon

Bu durumda ise sadece tek tür kaldıgından direkt olarak A template fonksiyonu tercih edilecek(argument deduction). Ve aşağıdaki imzaya sahip bir fonksiyon derleyici tarafından yazılacak:

void println(T) [with T = int]

Bu sayede println fonksiyonuna verdiğimiz değerlere uygun overload edilmiş println fonksiyonu çağıralarak ekrana bu değerler yazılmış olacak.

To be continued :))

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s