Մետածրագրավորում
Այս հոդվածը կարող է վիքիֆիկացման կարիք ունենալ Վիքիպեդիայի որակի չափանիշներին համապատասխանելու համար։ Դուք կարող եք օգնել հոդվածի բարելավմանը՝ ավելացնելով համապատասխան ներքին հղումներ և շտկելով բաժինների դասավորությունը, ինչպես նաև վիքիչափանիշներին համապատասխան այլ գործողություններ կատարելով։ |
Մետածրագրավորում-ը ծրագրավորման տեխնիկա է, որի կիրառման դեպքում ծրագիրն ինքը կարող է աշխատանքի ընթացքում կարդալ, գեներացնել, ստուգել կամ փոփոխել մեկ այլ ծրագրի կամ հենց ինքն իր կառուցվածքը (կոդը)[1][2]։ Շատ դեպքերում սա ծրագրավորողին օգնում է կրճատել կոդի տողերի քանակը և ծրագրավորման ժամանակը։ Այս ամենից բացի ծրագրերը դառնում են ավելի ճկուն և հարմարվում են նոր փոփոխությունների առանց նորից կոմպիլացվելու։
Մետածրագրավորման ձևերից մեկն է կաղապարների (template) միջոցով մետածրագրավորումը, երբ կաղապարներն օգտագործվում են կոմպիլիացիայի ժամանակ որևէ գործ կատարելու նպատակով։ Այս տեխնիկան օգտագործվում է հիմնականում C++, Curl, D, և XL լեզուներում, ինչպես նաև Lisp–ում՝ մակրոների միջոցով։
Մոտեցումներ
խմբագրելՄետածրագրավորումը հնարավորություն է տալիս գրել ծրագրեր կամ մշակել կոդ ընդհանուր ծրագրավորման պարադիգմի համատեքստում։
C++ կաղապարներ
խմբագրելC++ լեզուն հնարավորություն է տալիս գրել ընդհանրացված մեթոդ կամ դաս՝ առանց նշելու, թե որ տիպերի համար պետք է այն աշխատի։ Հետագայում, օգտագործելով այդ մեթոդը կամ դասը որևէ տիպի համար, կոմպիլիատորը գեներացնում է տվյալ կաղապարի համապատասխան կոդը՝ արդեն կոնկրետ նշված տիպի համար։ Հաշվի առնելով այն փաստը, որ կաղապարի կոդի գեներացիան կատարվում է կոմպիլիացիայի ժամանակ, հնարավորություն է ստեղծվում կաղապարների օգտագործմամբ հաշվել տարբեր արժեքներ կամ կատարել տարբեր խնդիրներ՝ առանց ծրագրի կատարման ընթացում ժամանակ կորցնելու։
Կաղապարի օրինակ՝
template <typename T>
inline T const& max (T const& a, T const& b) {
// եթե a < b, վերադարձնում է b, հակառակ դեպքում a:
return a < b ? b : a;
}
Տվյալ կաղապարային ֆունկցիան վերադարձնում է ստացված երկու արժեքներից մեծագույնը։ typename
֊ը տեղեկացնում է կոմպիլիատորին, որ T
֊ն տիպ է։ max
ֆունկացիան որևէ տիպի համար օգտագործելու դեպքում T–ն կփոխարինվի համապատասխան տիպով
և կգեներացվի տվյալ ֆունկցիային համապատասխան կոդը հենց այդ տիպի համար։
Սակայն max ֆունկացիան կանչելու դեպքում այն կաշխատի ծրագրի կատարման ընթացքում, իսկ մետածրագրավորում իրականացնելու համար
մեզ անհրաժեշտ է հաշվել արժեքներ ոչ թե ծրագրի կատարման ընթացքում, այլ կոմպիլիացիայի ժամանակ, դրանով իսկ դարձնելով ծրագրի
աշխատանքը ավելի արագ։
Ֆակտորիալի օրինակը
խմբագրելԿաղապարներով մետածրագրավորման օրինակ կարող է հանդիսանալ թվի ֆակտորիալի հաշվման ծրագիրը։
Թվի ֆակտորիալը կաղապարների միջոցով հաշվելը հնարավորություն է տալիս արդյունքը ստանալ կոմպիլիացիայի ժամանակ։ Վերը բերված max
ֆունկցիայի օրինակով հնարավոր չէ հասնել պահանջվող արդյունքին։ Անհրաժեշտ է ֆակտորիալ հաշվող ֆունկցիայում ունենալ ռեկուրսիվ կանչ։
template <int N>
struct Factorial {
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0> {
enum { value = 1 };
};
void foo() {
int x = Factorial<0>::value; // == 1
int y = Factorial<4>::value; // == 24
}
Այստեղ կոմպիլյատորը կաղապար գեներացնելու փոխարեն նախ հաշվում է value
֊ի արժեքը։ value
֊ի 0
արժեքի համար գրված է մեկ այլ կաղապար (Factorial–ի մասնավոր դեպք), որպես ռեկուրսիայի բազա։
enum
֊ի օգտագործումը հնարավորություն է տալիս ունենալ կոմպիլիացիայի ժամանակ հաշվարկվող արժեք։ Այս եղանակով x
֊ի և y
֊ի արժեքները հայտնի են դառնում արդեն ծրագրի կատարվելու պահին՝ առանց որևէ ժամանակային կորուստների։
C++11–ը մեզ հնարավորություն է տալիս անել նույնը առանց կաղապարներից օգտվելու, որը իրականացվում է constexpr–ի միջոցով։ constexpr–ը իրենից ներկայացնում է արտահայտություն, որի արժեքը հայտնի է կոմպիլյացիայի ժամանակ, կամ ֆունկցիա՝ որի վերադարձրած արժեքը հայտնի է կոմպիլյացիայի ժամանակ։
#include <iostream>
constexpr int factorial(int n)
{
return n ? (n * factorial(n - 1)) : 1;
}
int main()
{
constexpr int fact = factorial(10000);
std::cout << fact << std::endl;
return 0;
}
STL կոնտեյները
խմբագրելՍտանդարտ Կաղապարային Գրադարանը տարբերի խնդիրներ լուծելու համար ապահովում է մեծ թվով տվյալների կառուցվածքներ։ Այդ թվում նաև vector
, set
, list
, map
, queue
և այլ կոնտեյներները։ Բոլոր տվյալների կառուցվածքները կաղապարային դասեր են։ Օրինակ, ամբողջ թվերի vector
ստեղծելու համար պետք է նշել կաղապարային պարամետրը (տվյալ դեպքում՝ int
)։
std::vector<int> v(10);
for( int j = 0; j < 10; j++ )
v[j] = j * j;
Այս դեպքում կկառուցվի առաջին 10 ամբողջ թվերի քառակուսիները պարունակող vector
օբյեկտը։
Ծանոթագրություններ
խմբագրել- ↑ Course on Program Analysis and Transformation. By Prof. Harald Sondergaard.«Course on Program Analysis and Transformation». Վերցված է 2014 թ․ սեպտեմբերի 18-ին.
- ↑ Czarnecki, Krzysztof; Eisenecker, Ulrich W. (2000). Generative Programming. ISBN 0-201-30977-7.