Šablon metaprogramiranja

S Vikipedije, slobodne enciklopedije

Šablon metaprogramiranja (TMP) je tehnika metaprogramiranja  u kojoj šablone koristi kompajler za generisanje privremenog izvornog koda, koji je pripojen kompajleru sa ostatkom izvornog koda, a zatim sastavljen. Izlaz ovih šablona uključuje kompiliranja konstante, strukture podataka i kompletne funkcije. Korišćenje šablona može se posmatrati kao izvršenje kompiliranja. Tehnika se koristi od strane brojnih jezika, najpoznatiji su C++, ali takođe Curl, D, i XL.

Šablon metaprogramiranja je, u izvesnom smislu, otkriven slučajno.

Neki drugi jezici podržavaju sličan, ako ne i više moćno kompiliranje objekata (kao što je Lisp), ali oni su van obima ovog člana.

Komponente šablona metaprogramiranja[uredi | uredi izvor]

Korišćenje šablona kao tehnika metaprogramiranja zahteva dve odvojene operacije: šablon mora biti definisan, a definisan šablon mora biti instanciran. Definicija šablona opisuje opšti oblik generisanog izvornog koda, a instanciranje izaziva poseban set izvornog koda koji se generiše iz generičkog oblika u šablon.

Šablon metaprogramiranja je Tjuringova potpunost, što znači da svako ekspresno izračunavanje računarski program može da izračuna, u nekom obliku, od strane šablona metaprograma.[1]

Šabloni se razlikuju od makroa. Makro, što je takođe odlika kompiliranja jezika, generiše kod u-liniji koristeći manipulaciju teksta i zamenu. Makro sistemi često imaju ograničene sposobnosti kompiliranja  procesa protoka i obično nemaju svest o semantici i tipu sistema njihovog pratioca jezika (izuzetak treba da budu Lisp makroi, koji su napisani u samom Lisp-u i uključuju manipulaciju i zamenu Lisp koda predstavljen kao struktura podataka nasuprot tekstu). Šabloni  metaprogramiranja nemaju promenljive varijable- da se, bez promenljive može promeniti vrednost nakon što je inicijalizovana, stoga šablon metaprogramiranja može se posmatrati kao oblik funkcionalnog programiranja. U stvari, mnogi šabloni implementacije sprovode kontrolu protoka samo kroz rekurzije, kao što se vidi na primeru.

Korišćenje šablona metaprogramiranja[uredi | uredi izvor]

Iako se sintaksa šablona metaprogramiranja obično veoma razlikuje od programskog jezika sa kojim se koristi, ima praktične koristi. Neki uobičajeni razlozi da koriste šablone su da sprovedu generičko programiranje (izbegavajući delove koda koji su slični, osim nekih manjih varijacija) ili da vrši automatsku optimizaciju kompiliranja kao što rade nešto jednom u kompajliranju a ne svaki put da se program vodi - na primer, tako što kompajler odmotava petlje da eliminiše skokove i tačke petlje dekrementira kad god se izvršava program.

Kompiliranje klasa generacija[uredi | uredi izvor]

Šta tačno "programiranje  kompiliranjem" znači može se ilustrovati sa primerom faktorijel funkcija, koja u šabonlu C ++ može biti pisana korišćenjem rekurzije na sledeći način:

unsigned int factorial(unsigned int n) {
	return n == 0 ? 1 : n * factorial(n - 1);
}

// Примери коришћења:
// факторијал(0) би дало 1;
// факторијал(0) би дало 24.

Kod iznad će sprovesti u vreme izvršavanja za utvrđivanje faktorijalne vrednost literala 4 i 0. Pomoću šablona metaprogramiranja i šablona specijalizacije da obezbedi završni uslov za rekurzije, u faktorijalima koji se koriste u programu-ignoriše one faktorijale koji se ne koriste -mogu se izračunati  kompajliranjem ovim kodom: 

template <unsigned int n>
struct factorial {
	enum { value = n * factorial<n - 1>::value };
};

template <>
struct factorial<0> {
	enum { value = 1 };
};

// Примери коришћења:
// факторијал<0> :: вредност би дало 1;
// факторијал<0> :: вредност би дало 24.

Kod iznad izračunava faktorsku vrednost literala 4 i 0 u kompajliranju i koristi rezultat kao da su pre novosračunate konstante.

Da biste mogli da koristite šablone na ovaj način, prevodilac mora znati vrednost svojih parametara u kompajliranju, koji ima prirodni preduslov da faktorijalna <X> :: vrednost može se koristiti samo ako je X poznat u vreme kompilacije. Drugim rečima, X mora biti konstantna doslovno ili konstantan izraz.

U C++11, constexpr, način da se dozvoli prevodiocu da izvrši jednostavne izraze stalne, dodaje se. Koristeći constexpr, mogu se koristiti uobičajene rekurzivne faktorske definicije.[2]

Optimizacija kompiliranja koda[uredi | uredi izvor]

Faktorijal primer iznad  je jedan od primera kompiliranja optimizacije koda  da su svi faktorijalii korišćeni od strane programa unapred sastavljen i ubrizgava kao numeričke konstante na kompilaciji, štedi kako Run-time preko glave i memorije otiska. To je, međutim, relativno minorna optimizacija.

Kao drugo, još važnije, primer kompiliranja odmotavanja petlje, šablon metaprogramiranja se može koristiti za stvaranje dužina-n vektorskih časova (gde je n poznato na kompajliranje). Korist tokom tradicionalne dužine n vektora je da se petlje mogu odmotati, što dovodi do veoma optimiziranog koda. Kao primer, razmotrimo operatera dodataka. Dužine-N vektora dodatak može biti napisan kao

template <int length>
Vector<length>& Vector<length>::operator+=(const Vector<length>& rhs)
{
    for (int i = 0; i < length; ++i)
        value[i] += rhs.value[i];
    return *this;
}

Kada prevodilac instancira predložak funkcije ako što je definisano gore, sledeći kod mogže biti proizveden:

template <>
Vector<2>& Vector<2>::operator+=(const Vector<2>& rhs)
{
    value[0] += rhs.value[0];
    value[1] += rhs.value[1];
    return *this;
}

Optimizer kompajler treba da bude u stanju da razvijte for petlje jer parametar šablon length je konstanta u kompilaciji.

Međutim, uzeti oprez jer to može izazvati nadimanje koda, kao poseban odvijeni kod će se generisati za svaki 'N' (vektor veličine) možete instancirati.

Statički polimorfizam[uredi | uredi izvor]

Polimorfizam je zajednički standard programiranja objekata gde se izvedeni objekti mogu koristiti kao primeri njihovog osnovnog objekta, ali gde će biti pokrenute metode izvedenog objekata, kao u ovom kodu

class Base
{
public:
    virtual void method() { std::cout << "Base"; }
    virtual ~Base() {}
};

class Derived : public Base
{
public:
    virtual void method() { std::cout << "Derived"; }
};

int main()
{
    Base *pBase = new Derived;
    pBase->method(); // излаз "Derived"
    delete pBase;
    return 0;
}

gde će sva pozivanja na виртуелне metode biti ona od najvažnijih izvedenih klasa. Ovo dinamičko polimorfno ponašanje je (obično) dobijeno stvaranjem virtuelne luk ap tabele za odeljenja sa virtuelnim metodama, tabele koje su prevalile vreme izvršavanja da identifikuju način da budu pozvane. Tako, run-time polimorfizam nužno podrazumeva izvršenje iznad glave. Međutim, u mnogim slučajevima polimorfno ponašanje potrebno je da bude nepromenljivo i može biti određena u kompajliranju. Tada se Curiously Recurring Template Pattern (CRTP) može da koristi za postizanje statičkog polimorfizama, koji je imitacija polimorfizma u programskom kodu, ali koji je rešen u kompajliranju i na taj način ukida run-time virtuelne stolove. Na primer:

template <class Derived>
struct base
{
    void interface()
    {
         // ...
         static_cast<Derived*>(this)->implementation();
         // ...
    }
};

struct derived : base<derived>
{
     void implementation()
     {
         // ...
     }
};

Ovde osnovna klasa šablona će iskoristiti činjenicu da funkcije kao članovi organia nisu instancirane, tek posle njihove izjave, i to će koristiti članovi izvedene klase u okviru svojih funkcija članica, preko upotrebe static_cast, na kompilaciji generišući sastav objekta sa polimorfnim karakteristikama. Kao primer realnog-sveta koriste, CRTP se koristi u podsticaj iteratoru biblioteke.[3]

Još jedna slična upotreba je "Barton Nakmen trik", ponekad nazivaju "ograničen šablon proširenja", gde  zajednička funkcionalnost može biti postavljena u osnovne klase koja se ne koristi kao ugovor već kao neophodna komponenta da se sprovede usklađenost ponašanja, dok minimizira lod redundantnost.

Prednosti i nedostaci šablona metaprogramiranja[uredi | uredi izvor]

Kompiliranje naspram izvršenje vremena kompromis
Ako se koristi veliki deo šablona metaprogramiranja, kompilacija može da postane spora; sekcija 14.7.1  aktuelnog standarda definiše okolnosti pod kojima se šabloni implicitno instanciraju. Definisanje šablona ne znači da će biti instanciran, a instanciranje klase šablona ne izaziva svoje definicije članicama da se instanciraju  U zavisnosti od stila upotrebe, šabloni se mogu sastaviti bilo brže ili sporije nego što predaju valjani kod.
Generičko programiranje
Šablon metaprogramiranja omogućava programeri da se fokusira na arhitekturu i delegatu za kompajlersko stvaranje bilo kakve realizacije zahteva klijenta koda. Tako, šablon metaprogramiranja može da ostvari istinski generički kod, olakšavanje minimiziranje koda  i bolje održavanje.
Čitljivost
Što se tiče C ++, sintaksa i idiomi šablona metaprogramiranja su ezoterične poređenju sa konvencionalnim C ++ programiranjem i šablon metaprogramiranja može biti veoma težak za razumevanje. [4][5]

Vidi još[uredi | uredi izvor]

Reference[uredi | uredi izvor]

  1. ^ Veldhuizen, Todd L. "C++ Templates are Turing Complete" Arhivirano na sajtu Wayback Machine (23. novembar 2015) (PDF). http://ubietylab.net/ Arhivirano na sajtu Wayback Machine (17. jun 2016).
  2. ^ Constexpr - Generalized Constant Expressions in C++11 - Cprogramming.com
  3. ^ Iterator Facade - 1.60.0
  4. ^ Czarnecki, K.; O’Donnell, J.; Striegnitz, J.; Taha, Walid Mohamed (2004).
  5. ^ Sheard, Tim; Jones, Simon Peyton (2002).

Literatura[uredi | uredi izvor]

Dodatna literatura[uredi | uredi izvor]

Spoljašnje veze[uredi | uredi izvor]