Шаблон метапрограмирања

Из Википедије, слободне енциклопедије

Шаблон метапрограмирања (ТМП) је техника метапрограмирања  у којој шаблоне користи компајлер за генерисање привременог изворног кода, који је припојен компајлеру са остатком изворног кода, а затим састављен. Излаз ових шаблона укључује компилирања константе, структуре података и комплетне функције. Коришћење шаблона може се посматрати као извршење компилирања. Техника се користи од стране бројних језика, најпознатији су C++, али такође Curl, D, и XL.

Шаблон метапрограмирања је, у извесном смислу, откривен случајно.

Неки други језици подржавају сличан, ако не и више моћно компилирање објеката (као што је Lisp), али они су ван обима овог члана.

Компоненте шаблона метапрограмирања[уреди]

Коришћење шаблона као техника метапрограмирања захтева две одвојене операције: шаблон мора бити дефинисан, а дефинисан шаблон мора бити инстанциран. Дефиниција шаблона описује општи облик генерисаног изворног кода, а инстанцирање изазива посебан сет изворног кода који се генерише из генеричког облика у шаблон.

Шаблон метапрограмирања је Тјурингова потпуност, што значи да свако експресно израчунавање рачунарски програм може да израчуна, у неком облику, од стране шаблона метапрограма.[1]

Шаблони се разликују од макроа. Макро, што је такође одлика компилирања језика, генерише код у-линији користећи манипулацију текста и замену. Макро системи често имају ограничене способности компилирања  процеса протока и обично немају свест о семантици и типу система њиховог пратиоца језика (изузетак треба да буду Lisp макрои, који су написани у самом Lisp-у и укључују манипулацију и замену Lisp кода представљен као структура података насупрот тексту). Шаблони  метапрограмирања немају променљиве варијабле- да се, без променљиве може променити вредност након што је иницијализована, стога шаблон метапрограмирања може се посматрати као облик функционалног програмирања. У ствари, многи шаблони имплементације спроводе контролу протока само кроз рекурзије, као што се види на примеру.

Коришћење шаблона метапрограмирања[уреди]

Иако се синтакса шаблона метапрограмирања обично веома разликује од програмског језика са којим се користи, има практичне користи. Неки уобичајени разлози да користе шаблоне су да спроведу генеричко програмирање (избегавајући делове кода који су слични, осим неких мањих варијација) или да врши аутоматску оптимизацију компилирања као што раде нешто једном у компајлирању а не сваки пут да се програм води - на пример, тако што компајлер одмотава петље да елиминише скокове и тачке петље декрементира кад год се извршава програм.

Компилирање класа генерација[уреди]

Шта тачно "програмирање  компилирањем" значи може се илустровати са примером факторијел функција, која у шабонлу C ++ може бити писана коришћењем рекурзије на следећи начин:

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

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

Код изнад ће спровести у време извршавања за утврђивање факторијалне вредност литерала 4 и 0. Помоћу шаблона метапрограмирања и шаблона специјализације да обезбеди завршни услов за рекурзије, у факторијалима који се користе у програму-игнорише оне факторијале који се не користе -могу се израчунати  компајлирањем овим кодом: 

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

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

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

Код изнад израчунава факторску вредност литерала 4 и 0 у компајлирању и користи резултат као да су пре новосрачунате константе.

Да бисте могли да користите шаблоне на овај начин, преводилац мора знати вредност својих параметара у компајлирању, који има природни предуслов да факторијална <X> :: вредност може се користити само ако је X познат у време компилације. Другим речима, X мора бити константна дословно или константан израз.

У C++11, constexpr, начин да се дозволи преводиоцу да изврши једноставне изразе сталне, додаје се. Користећи constexpr, могу се користити уобичајене рекурзивне факторске дефиниције.[2]

Оптимизација компилирања кода[уреди]

Факторијал пример изнад  је један од примера компилирања оптимизације кода  да су сви факторијалии коришћени од стране програма унапред састављен и убризгава као нумеричке константе на компилацији, штеди како Рун-тиме преко главе и меморије отиска. То је, међутим, релативно минорна оптимизација.

Као друго, још важније, пример компилирања одмотавања петље, шаблон метапрограмирања се може користити за стварање дужина-н векторских часова (где је н познато на компајлирање). Корист током традиционалне дужине н вектора је да се петље могу одмотати, што доводи до веома оптимизираног кода. Као пример, размотримо оператера додатака. Дужине-Н вектора додатак може бити написан као

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;
}

Када преводилац инстанцира предложак функције ако што је дефинисано горе, следећи код могже бити произведен:

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

Оптимизер компајлер треба да буде у стању да развијте for петље јер параметар шаблон length је константа у компилацији.

Међутим, узети опрез јер то може изазвати надимање кода , као посебан одвијени код ће се генерисати за сваки 'N' (вектор величине) можете инстанцирати.

Статички полиморфизам[уреди]

Полиморфизам је заједнички стандард програмирања објеката где се изведени објекти могу користити као примери њиховог основног објекта, али где ће бити покренуте методе изведеног објеката, као у овом коду

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;
}

где ће сва позивања на виртуелне методе бити она од најважнијих изведених класа. Ово динамичко полиморфно понашање је (обично) добијено стварањем виртуелне лук ап табеле за одељења са виртуелним методама, табеле које су превалиле време извршавања да идентификују начин да буду позване. Тако, рун-тиме полиморфизам нужно подразумева извршење изнад главе. Међутим, у многим случајевима полиморфно понашање потребно је да буде непроменљиво и може бити одређена у компајлирању. Тада се Curiously Recurring Template Pattern (CRTP) може да користи за постизање статичког полиморфизама, који је имитација полиморфизма у програмском коду, али који је решен у компајлирању и на тај начин укида рун-тиме виртуелне столове. На пример:

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

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

Овде основна класа шаблона ће искористити чињеницу да функције као чланови органиа нису инстанциране, тек после њихове изјаве, и то ће користити чланови изведене класе у оквиру својих функција чланица, преко употребе static_cast, на компилацији генеришући састав објекта са полиморфним карактеристикама. Као пример реалног-света користе, ЦРТП се користи у подстицај итератору библиотеке.[3]

Још једна слична употреба је "Бартон Накмен трик", понекад називају "ограничен шаблон проширења", где  заједничка функционалност може бити постављена у основне класе која се не користи као уговор већ као неопходна компонента да се спроведе усклађеност понашања, док минимизира лод редундантност.

Предности и недостаци шаблона метапрограмирања[уреди]

Компилирање наспрам извршење времена компромис
Ако се користи велики део шаблона метапрограмирања, компилација може да постане спора; секција 14.7.1  актуелног стандарда дефинише околности под којима се шаблони имплицитно инстанцирају. Дефинисање шаблона не значи да ће бити инстанциран, а инстанцирање класе шаблона не изазива своје дефиниције чланицама да се инстанцирају  У зависности од стила употребе, шаблони се могу саставити било брже или спорије него што предају ваљани код.
Генеричко програмирање
Шаблон метапрограмирања омогућава програмери да се фокусира на архитектуру и делегату за компајлерско стварање било какве реализације захтева клијента кода. Тако, шаблон метапрограмирања може да оствари истински генерички код, олакшавање минимизирање кода  и боље одржавање.
Читљивост
Што се тиче C ++, синтакса и идиоми шаблона метапрограмирања су езотеричне поређењу са конвенционалним C ++ програмирањем и шаблон метапрограмирања може бити веома тежак за разумевање. [4][5]

Види још[уреди]

Референце[уреди]

  1. Veldhuizen, Todd L. "C++ Templates are Turing Complete" (PDF). http://ubietylab.net/.
  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).

Литература[уреди]

  • Eisenecker, Ulrich W. Generative Programming: Methods, Tools, and Applications. Addison-Wesley. ISBN 0-201-30977-7.
  • Alexandrescu, Andrei. Modern C++ Design: Generic Programming and Design Patterns Applied. Addison-Wesley. ISBN 3-8266-1347-3.
  • Abrahams, David; Gurtovoy, Aleksey. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond. Addison-Wesley. ISBN 0-321-22725-5.
  • Vandervoorde, David; Josuttis, Nicolai M. C++ Templates: The Complete Guide. Addison-Wesley. ISBN 0-201-73484-2.
  • Clavel, Manuel. Reflection in Rewriting Logic: Metalogical Foundations and Metaprogramming Applications. ISBN 1-57586-238-7.

Спољашње везе[уреди]