Szablony (ang. template) są jednym z podejść do programowania uogólnionego. Szablony w D są bardzo podobne do szablonów i przestrzeni nazw w C++. Można im nadawać osobne funkcjonujące niezależnie nazwy przez co zachowują się wtedy jak sparametryzowana przestrzeń nazw. Szablony w D tworzy się następująco: template Nazwa(T) { //deklaracje funkcji, klas, zmiennych int func(T arg) { return sizeof(arg);

Gdzie Nazwa jest szablonową przestrzenią nazw o parametrze T. Używanie szablonów w programie następuje poprzez poprzedzenie listy parametrów w nawiasach okrągłych wykrzyknikiem. Nazwa!(long).func(10); Nazwa!(int[]).func(1,2,3,4,5,6,7,8,9,10);

Klasy szablonowe i funkcje

Klasy i funkcje szablonowe można tworzyć na 2 sposoby. Długi poprzez umieszczenie klasy/funkcji o nazwie takiej samej jak szablon lub w krótszy sposób poprzez umieszczenie listy parametrów zaraz za deklaracją nazwy klasy/funkcji.

class MojaKlasa(T) { // klasa szablonowa z parametrem T }

int func(T)(T arg) { // funkcja szablonowa } Użycie jest podobne do zwykłych szablonów, ale można pominąć wtedy przestrzeń nazw: MojaKlasa!(int) a = new MojaKlasa!(int); func(52);

Zmienna liczba parametrów szablonu

W D istnieje możliwość tworzenia szablonów z nieokreśloną liczbą parametrów, co może być w wielu przypadkach bardzo użyteczne. real sum(T...)(T args) { real ret = 0; foreach(a; args) ret += a; return ret; // zwróci sumę wszystkich argumentów jako liczbę rzeczywistą } Użycie takiej funkcji jest o tyle proste, że nie trzeba wymieniać wszystkich argumentów: sum(12,34434.42432,32453235432,21421,124,2424.2342,214124.5);

Metaprogramowanie z wykorzystaniem szablonów

Metaprogramowanie w D jest znacznie ułatwione dzięki zastosowaniu instrukcji warunkowej kompilacji "static if". Przykładowo szablon liczący silnię z podanej liczby (por. silnia w czasie kompilacji (c++)):

template Silnia(N) { static if(N==0) // statyczny if enum Silnia = 1; else enum Silnia = Silnia!(N-1)*N; } Gdzie N to parametr określający liczbę z jakiej liczymy silnię.

Kompilatory D pozwalają również na wykonywanie funkcji "czystych" (ang. pure) w czasie kompilacji, tak więc powyższy szablon można zastąpić zwykłą funkcją: int silnia(int n) { return (n == 1) ? 1 : n * silnia(n-1); }

static int x = silnia(5);

Wartość zmiennej x będzie obliczona w czasie kompilacji.

Można to sprawdzić, korzystając z możliwości D operowania na ciągach znaków w czasie kompilacji oraz z instrukcji kompilatora pragma(msg,): template itoa(long i) { static assert (i > 0); static if (i < 10) const char[] itoa = "" ~ cast(char)(i + '0'); else const char[] itoa = itoa!(i / 10) ~ itoa!(i % 10); }

pragma(msg, itoa!(silnia(6));

Ponieważ szablon itoa parametryzowany jest wartością typu long, użyta jest instrukcja warunkowej kompilacji static assert, może ona być pominięta, jeśli typ argumentu i zostanie zmieniony na ulong.

Instrukcja ta spowoduje przerwanie kompilacji, jeśli podany argument jest liczbą ujemną.

Przypisy

Bibliografia

Kategoria:Konstrukcje programistyczne