std.typetuple modülünün olanağı olan TypeTuple şuradaki bölümün sonunda çok kısa olarak geçmişti:
http://ddili.org/ders/d/cokuzlular.html
(O bölüm bu mesajdan bir kaç hafta sonra iki bölüme ayrılacak.)
Öncelikle oradaki çokuzlu (tuple) kavramını anlamak gerekiyor. Ben TypeTuple'ın kullanım örneklerini biliyordum ve gerektiğinde istediğim sonucu alabiliyordum. TypeTuple'ın tam olarak ne olduğunu çok yeni anladım.
TypeTuple, parametre listesi denen D olanağını oluşturmaya ve yönetmeye yarıyor. Parametre listesi işlevlerde ve şablonlarda hep karşımıza çıkar:
void işlev(int i, string s, double d)
{
// ...
}
struct Yapı(string s, double d, float f)
{
// ...
}
Yukarıda bir işlev ve bir yapı şablonu var. Normalde her ikisini de açıkça üç parametre değeri ile kullanabiliriz.
TypeTuple, parametre listesi kavramını programcıya sunuyor:
alias parametreler = TypeTuple!(42, "merhaba", 1.5);
'parametreler' artık (42, "merhaba", 1.5) gibi bir parametre listesini temsil ediyor. Örneğin, işlevi yalnızca 'parametreler' ile çağırabiliriz:
işlev(parametreler); // aslında üç parametre gönderiliyor
TypeTuple dizi işleçleriyle kullanılabiliyor: 'parmetreler[ i ]' yasal... Başka örnek:
auto nesne = Yapı!(parametreler[1..$], 2.5)();
Bir anlamda, TypeTuple her yerleştiği yere parametre listesi olarak açılmış oluyor. Hepsi aynı türden olsa dizi elemanları için de kullanılabiliyor:
auto diziElemanları = TypeTuple!(1, 2, 3, 4);
auto dizi = [ diziElemanları ];
Yukarıdaki gibi yerel parametre listesi oluşturmak pek yaygın bir ihtiyaç değil. TypeTuple'lar en çok belirsiz sayıda parametreyle (variadic function, veya variadic template) ilgilenirken işe yarıyor:
long topla(T...)(T parametreler)
{
// T, bir TypeTuple'dur
}
Yukarıdaki işlev şablonu belirsiz sayıda parametreyle çağrılabilir:
topla(1, 2, 3)
Tabii işin güzeli, kendisi bir şablon olduğundan bütün parametrelerinin aynı türden değerler olmaları gerekmiyor. Garip bir örnek olarak yalnızca int'leri toplayan bir işleve bakalım:
long intleriTopla(T...)(T parametreler)
{
long sonuç = 0;
foreach (parametre; parametreler) {
static if (is (typeof(parametre) == int)) {
sonuç += parametre;
}
}
return sonuç;
}
(Not: Aşağıdaki bütün programdaki bir açıklamada göreceğiniz gibi, yukarıdaki foreach derleme zamanında kod açılımıdır; çalışma zamanında döngü değildir.)
Aşağıdaki örnek yalnızca int olan parametreleri topluyor:
assert(intleriTopla(10, "merhaba", 2.5, 20) == 30);
Aşağıdaki örnek işlev writefln gibi işliyor ama düzen bilgisini her değerden önce alıyor (kodu aşağıdaki programda):
benimWritefln("(%s)", 1, "{%s}", 2, " üçüncü değer: %s", 3);
Yani, yukarıdaki çağrı aşağıdakinin eşdeğeri:
writefln("(%s){%s} üçüncü değer: %s", 1, 2, 3);
Dediğim gibi, saçma bir örnek... :)
Bütün program aşağıda... TypeTuple da bütünüyle derleme zamanı olanağı olduğu için foreach'ler aslında kod olarak açılırlar ve static if gibi derleme zamanı olanaklarını kullanmak gerekiyor.
import std.stdio;
import std.typetuple;
void işlev(int i, string s, double d)
{
writefln("işlev çağrıldı: %s %s %s", i, s, d);
}
struct Yapı(string s, double d, float f)
{
void üyeİşlev()
{
writefln("Yapının şablon parametreleri: %s %s %s", s, d, f);
}
}
long topla(T...)(T parametreler)
{
// T, bir TypeTuple'dur
long sonuç = 0;
foreach (değer; parametreler) {
sonuç += değer;
}
/*
* UYARI:
*
* Yukarıdaki foreach çalışma zamanında işletilen bir döngü değildir;
* foreach'in içindeki işlemlerin derleme zamanında kod içine gereken
* sayıda açılmasından üretilen bir kod bloğudur. Örneğin, 3 parametre ile
* çağrıldığında yukarıdaki döngü şunun eşdeğeridir:
*
* {
* sonuç += parametreler[0];
* }
* {
* sonuç += parametreler[1];
* }
* {
* sonuç += parametreler[2];
* }
*/
return sonuç;
}
long intleriTopla(T...)(T parametreler)
{
long sonuç = 0;
foreach (parametre; parametreler) {
static if (is (typeof(parametre) == int)) {
sonuç += parametre;
}
}
return sonuç;
}
/*
* Parametreler çift sayıda olmalıdır: Önce düzen dizgisi, sonra değer.
*/
void benimWritefln(T...)(T parametreler)
if ((parametreler.length % 2) == 0)
{
string düzen;
foreach (i, parametre; parametreler) {
static if ((i % 2) == 0) {
// Bu, düzen belirteci. Önce string olduğunu denetleyelim
static assert(is (typeof(parametre) == string));
düzen = parametre;
} else {
// Bu, yazdırılacak olan değer. Yazdıralım...
writef(düzen, parametre);
}
}
// Sondaki satır sonu
writeln();
}
void main()
{
alias parametreler = TypeTuple!(42, "merhaba", 1.5);
işlev(parametreler);
auto nesne = Yapı!(parametreler[1..$], 2.5)();
nesne.üyeİşlev();
auto diziElemanları = TypeTuple!(1, 2, 3, 4);
auto dizi = [ diziElemanları ];
writefln("dizi: %s", dizi);
writefln("toplam: %s", topla(1, 2, 3));
assert(intleriTopla(10, "merhaba", 2.5, 20) == 30);
writefln("int'lerin toplamı: %s", intleriTopla(10, "merhaba", 2.5, 20));
benimWritefln("(%s)", 1, "{%s}", 2, " üçüncü değer: %s", 3);
/* Üsttekinin eşdeğeri:
*
* writefln("(%s){%s} üçüncü değer: %s", 1, 2, 3);
*/
}
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]