Структура на шаблон в. Шаблони

10.1. Дефинирање на шаблон за функција

Понекогаш може да изгледа дека силно напишаниот јазик го отежнува спроведувањето на било што. едноставни функции. На пример, иако следниот алгоритамФункцијата min() е тривијална, силното пишување бара нејзини варијации да се имплементираат за сите типови што ќе ги споредиме:

int min(int a, int b) (

врати a b ? а: б;

двојно мин (двојно а, двојно б) (

врати a b ? а: б;

Примамлива алтернатива за експлицитно дефинирање на секоја инстанца на min() е да се користат макроа што можат да се прошират предпроцесор:

#define min(a, b) ((a) (b) ? (a) : (b))

Но, овој пристап е полн со потенцијални опасности. Макрото дефинирано погоре работи правилно со едноставни повици до min(), на пример:

мин (10.0, 20.0);

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

#вклучи iostream

#define min(a,b) ((a) (b) ? (a) : (b))

const int големина = 10;

додека (min(p++,ia) != ia)

cout "elem_cnt: "elem_cnt

" очекување: " големина endl;

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

elem_cnt: 5 очекуваат: 10

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

Шаблонот го дава алгоритмот што се користи за автоматско генерирањефункционални инстанци со разни видови. Програмерот ги параметриизира сите или само некои типови во интерфејсот на функцијата (т.е. формалниот параметар и типовите повратни вредности), оставајќи го неговото тело непроменето. Функцијата е добро прилагодена да биде шаблон ако нејзината имплементација останува непроменлива во одреден сет на примери кои се разликуваат во типовите на податоци, како, на пример, во случајот min().

Вака е дефиниран шаблонот за функција min():

шаблон класа Тип

Тип min2 (тип a, тип b) (

врати a b ? а: б;

// точно: min(int, int);

// точно: мин (двојно, двојно);

мин (10.0, 20.0);

Ако наместо претпроцесор, во текстот се замени макрото min(). претходна програмаоваа шема, тогаш резултатот ќе биде точен:

elem_cnt: 10 очекување: 10

(ВО стандардна библиотека C++ има шаблони за функции за многу често користени алгоритми, како што е min(). Овие алгоритми се опишани во Поглавје 12. И во ова воведно поглавје ги презентираме нашите сопствени поедноставени верзии на некои од алгоритмите во стандардната библиотека.)

И декларацијата и дефиницијата на шаблон за функција мора секогаш да започнуваат со шаблонот за клучни зборови, проследени со листа на идентификатори одвоени со запирки, затворени во аголни загради " и " - список со параметри на шаблонот, кој не мора да биде празен. Шаблонот може да има параметри на тип, кои претставуваат тип, и константни параметри, кои претставуваат фиксен константен израз.

Параметарот тип се состои од клучен збор класа или клучен збор typename проследено со идентификатор. Овие зборови секогаш укажуваат дека следното име се однесува на вграден или дефиниран тип од корисникот. Името на параметарот на шаблонот го избира програмерот. Во примерот погоре, го користевме името Тип, но можевме да избереме нешто друго:

шаблон класа Glorp

Glorp min2(Glorp a, Glorp b) (

врати a b ? а: б;

При инстантирање (создавање специфичен пример) шаблон, вистинскиот вграден или дефиниран од корисникот тип се заменува со параметарот тип. Било кој од типовите int, double, char*, vectorint или listdouble е валиден шаблон аргумент.

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

шаблон класа Тип, int големина

Тип min(Тип (arr) );

По списокот со параметри на шаблонот следи декларација или дефиниција за функција. Ако не обрнете внимание на присуството на параметри во форма на спецификатори на тип или константи, тогаш дефиницијата за шаблон за функции изгледа сосема исто како и за обичните функции:

шаблон класа Тип, int големина

/* параметризирана функција за пребарување

* минимална вредноство низа */

Тип min_val = r_ низа;

за (int i = 1; i големина; ++i)

ако (r_низа[i] min_val)

min_val = r_низа[i];

Во овој пример, Type го одредува типот на вредноста што ја враќа функцијата min(), типот на параметарот r_array и типот на локалната променлива min_val; големината ја одредува големината на низата r_array. За време на работата на програмата, при користење на функцијата min(), било која вградена и дефинирани од корисникоттипови, а наместо големина - одредени постојани изрази. (Потсетете се дека можете да работите со функција на два начина: повикајте ја или земете ја нејзината адреса).

Процесот на замена на типови и вредности за параметри се нарекува инстанција на шаблон. (Ќе навлеземе во повеќе детали за ова во следниот дел.)

Списокот на параметри за нашата функција min() може да изгледа многу краток. Како што беше дискутирано во делот 7.3, кога параметарот е низа, се пренесува покажувач до неговиот прв елемент, но првата димензија на вистинскиот аргумент на низата во рамките на дефиницијата на функцијата е непозната. За да ја надминеме оваа тешкотија, првиот параметар го прогласивме за min() како референца за низата, а вториот како нејзина големина. Недостаток на овој пристап е тоа што кога се користи шаблон со низи од истите напишете int, Но различни големиниразлични инстанци од функцијата min() се генерираат (или инстанцирани).

Името на параметарот е дозволено да се користи во шаблон декларација или дефиниција. Параметарот тип служи како спецификатор на типот; може да се користи исто како и секој вграден или прилагоден тип, на пример во декларации на променливи или операции за леење типови. Константен параметар се користи како константна вредност - каде што се потребни константни изрази, на пример за да се специфицира големината во декларацијата на низата или како почетна вредност на елементот за набројување.

// големината ја одредува големината на параметарот на низата и се иницијализира

// тип променлива const int

шаблон класа Тип, int големина

Тип min(const тип (r_array))

const int loc_size = големина;

Напишете loc_array;

Ако објект, функција или тип со исто име како параметар на шаблонот се декларира во глобалниот опсег, тогаш глобално имеиспаѓа дека е скриен. Во следниот пример, типот на променливата tmp не е двоен, туку ист како параметарот на шаблонот Type:

typedef double Тип;

шаблон класа Тип

Тип min (тип a, тип b)

// tmp е ист тип како параметарот на шаблонот Тип, а не дадениот

// глобален типдеф

Тип tm = a b ? а: б;

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

шаблон класа Тип

Тип min (тип a, тип b)

// грешка: повторена декларација на името Тип што одговара на името

// параметар на шаблон

typedef double Тип;

Тип tmp = a b ? а: б;

Името на параметарот тип на шаблон може да се користи за да се одреди типот на враќање:

// точно: T1 го претставува типот на вредност вратена со min(),

// и T2 и T3 се типските параметри на оваа функција

шаблон класа Т1, класа Т2, класа Т3

Во една листа на параметри, одредено име е дозволено да се користи само еднаш. На пример, следнава дефиниција ќе биде означена како грешка при компилација:

// грешка: неточно повторна употребаиме на параметар Тип

шаблон класа Тип, класа Тип

Тип min (Тип, Тип);

Сепак, истото име може да се користи повеќе пати во декларација или дефиниција на шаблон:

// точно: повторно користење на името на типот во шаблонот

шаблон класа Тип

Тип min (Тип, Тип);

шаблон класа Тип

Тип макс (Тип, Тип);

Имињата на параметрите во декларацијата и дефиницијата не мора да се совпаѓаат. Така, сите три декларации min() се однесуваат на истиот функционален шаблон:

// сите три декларации min() се однесуваат на истиот функционален шаблон

// препрати декларации за шаблоните

шаблон класа T T min(T, T);

шаблон класа U U min(U, U);

// вистинска дефиниција на шаблон

шаблон класа Тип

Тип min(тип a, тип b) ( /* ... */ )

Неограничен е бројот на појавувања на истиот параметар на шаблонот во списокот со параметри на функцијата. Следниот пример користи Type за да претстави два различни параметри:

// точно: Типот се користи постојано во списокот со параметри на шаблонот

шаблон класа Тип

Тип сума (const vectorType , Type);

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

// точно: името на типот и клучните зборови на класата може да се испреплетени

шаблон за тип T, класа U

// грешка: мора да биде името на типот T, класата U или

// име на тип T, име на тип U

име на шаблон T, U

Во списокот со параметри на шаблонот за функции, клучните зборови typename и class имаат исто значење и затоа се заменливи. Било од овие може да се користи за декларирање на различни параметри за тип на шаблон во истата листа (како што е прикажано со шаблонот на функцијата minus()). За да се означи параметарот на типот, на прв поглед е поприродно да се користи клучниот збор typename наместо класа, бидејќи тој јасно покажува дека е проследен со име на тип. Сепак, овој збор неодамна беше додаден на јазикот како дел од стандардот C++, така што најверојатно ќе го видите зборот класа во постарите програми. (Да не зборуваме дека класата е пократка од името на типот, а луѓето се мрзливи по природа.)

Клучниот збор typename го олеснува анализирањето на дефинициите на шаблоните. (Ќе се задржиме само накратко зошто тоа беше потребно. За оние кои сакаат да дознаат повеќе за ова, препорачуваме да се повикаат на книгата на Струструп „Дизајн и еволуција на C++“.)

При парсирање на овој начин, компајлерот мора да разликува изрази што се типови од оние што не се; не е секогаш можно да се идентификува ова. На пример, ако компајлерот го сретне изразот Parm::name во дефиниција на шаблон, и ако Parm е тип параметар што претставува класа, дали името треба да се претпостави дека претставува член на типот на класата Parm?

шаблон класа Parm, класа U

Парм::име * стр; // дали е ова декларација на покажувачот или множење?

// Всушност множење

Компајлерот не знае дали името е тип бидејќи дефиницијата за класата претставена со Parm не е достапна додека шаблонот не се инстанцира. За таква дефиниција за шаблон да се анализира, корисникот мора да му каже на компајлерот кои изрази ги вклучуваат типовите. Ова се прави со користење на клучниот збор typename. На пример, ако сакаме изразот Parm::name во шаблонот на функцијата minus() да биде име на тип и затоа целата линија да се третира како декларација на покажувачот, тогаш треба да го измениме текстот на следниов начин:

шаблон класа Parm, класа U

Парм минус (низа парм*, вредност U)

име на тип Парм::име * стр; // сега ова е декларација за покажувач

Клучниот збор typename исто така се користи во списокот со параметри на шаблон за да покаже дека параметарот е тип.

Шаблон за функција може да се декларира како внатрешен или надворешен - исто како редовна функција. Спецификаторот се става по списокот со параметри, а не пред шаблонот за зборови.

// точно: спецификатор по листа на параметри

име на тип на шаблон Тип

Тип min (Тип, Тип);

// грешка: Вградениот спецификатор не е на место

име на тип на шаблон Тип

Тип min(ArrayType, int);

Вежба 10.1

Определете која од овие дефиниции за шаблоните за функции е неточна. Поправете ги грешките.

(а) шаблон класа T, U, класа V

void foo (T, U, V);

(б) шаблон класа Т

(в) шаблон класа Т1, име на тип Т2, класа Т3

(г) Име на типот на вграден шаблон Т

T foo(T, непотпишан int*);

(д) шаблон класа myT, класа myT

void foo(myT, myT);

(ѓ) шаблон класа Т

(е) typedef char Ctype;

шаблон класа Тип

Ctype foo(Ctype a, Ctype b);

Вежба 10.2

Кои од повторените декларации на шаблоните се погрешни? Зошто?

(а) шаблон класа Тип

Тип лента (Тип, Тип);

шаблон класа Тип

Тип лента (Тип, Тип);

(б) шаблон класа Т1, класа Т2

празна прачка (T1, T2);

име на шаблон C1, име на тип C2

празна прачка (C1, C2);

Вежба 10.3

Препишете ја функцијата putValues() од Дел 7.3.3 како шаблон. Параметризирајте го така што ќе има два параметри на шаблонот (за типот на елементите на низата и за големината на низата) и еден функционален параметар кој е референца за низата. Напишете дефиниција за шаблон за функција.

Од книгата Microsoft Office автор Леонтиев Виталиј Петрович

Избор на шаблон Како што веќе рековме, Publisher е дизајниран да работи во режим „чекор-по-чекор“ - ние, како да беше, составуваме идна публикација дел по дел. И уште попрецизно, го создаваме врз основа на еден од безбројните шаблони. На ЦД-то на Publisher се зачувани повеќе од една и пол илјади шаблони

Од книгата Водич за помошво C++ автор Строустрап Бјарне

Р.7.1.4 Спецификации за тип на шаблон Спецификација за тип на шаблон се користи за одредување фамилија на типови или функции (види

Од книгата Ефективна канцелариска работа автор Пташински Владимир Сергеевич

Концептот на шаблон За да се поедностави работата на креирање и форматирање текстови, стандардизирање на распоредот и дизајнот на текстот, графиката, типизирањето на операциите за обработка на документи и други работи, се користат шаблони за документи. Microsoft пакет Office дава различни дефиниции за шаблон

Од книгата Обработка на бази на податоци во Visual Basic®.NET автор Мекманус Џефри П

Од книгата Создавање Шаблони за џумла автор Непознат автор

Структура на директориумот на шаблоните Сега треба да се грижиме за некои услови. Како што веќе споменавме, шаблонот мора да има одредена структура на директориум: [PathToJoomla!]/templates/[TemplateName]/[PathToJoomla!]/templates/[TemplateName]/css/[PathToJoomla!]/templates/[

Од книгата XSLT автор Холцнер Стефан

Структура на шаблон Покрај посебен наслов, на шаблонот му е потребна структура. Можете да креирате структура користејќи табели или ознаки

. Следно, опишуваме создавање табеларна верзија на структурата. Ако сè уште имате овозможен режим на распоред во Dremweaver, затворете

Од книгата XSLT Technology автор Валиков Алексеј Николаевич

Креирање на шаблон Во поглавје 2, создадов основен шаблон за избирање јазли во planets.xml и конвертирање на тој документ во HTML. Шаблоните во стилските листови се креираат со помош на елементи , дефинирајќи ги правилата за потребните трансформации. Создадовме шаблон што го најде коренот

Од книгата Програмскиот јазик C за персонален компјутер автор Бочков С.О.

Тело на шаблонот Всушност, елементот xsl:template што го дефинира правилото за шаблон не специфицира ништо повеќе од условите под кои правилото треба да се изврши. Специфичните дејства и инструкции што мора да се извршат се одредени од содржината на елементот xsl:template и сочинуваат

Од книгата Јазикот Ц - Водич за почетници од Прата Стивен

Дефиниција на функција Дефиницијата на функцијата го одредува името, формалните параметри и телото на функцијата. Може да го специфицира и типот на враќање на функцијата и класата за складирање. Синтаксата за дефинирање на функцијата е:[<спецификация КП>][<спецификация

Од книгата Недокументирани и малку познати карактеристики на Windows XP автор Клименко Роман Александрович

Дефинирање на функција со аргумент: Формални аргументи Дефиницијата на функцијата започнува со две линии: space(number)int number Првата линија го информира компајлерот дека функцијата space() има аргумент и дека нејзиното име е број. Втората линија е опис што укажува

Од книгата Како да направите сопствена веб-страница и да заработите пари на неа. Практичен водич за почетници за правење пари онлајн автор Мухутдинов Евгениј

Креирање безбедносен образец За да креирате безбедносен образец заснован на кој било друг шаблон, изберете ја командата Зачувај како од контекстното мени на шаблонот. Конзолата за управување на Microsoft потоа ќе ве поттикне да наведете име за новиот шаблон, по што ќе се појави во

Од книгата C++ за почетници од Липман Стенли

Од книгата на авторот

10.2. Одредување на шаблон за функција Шаблонот за функција опишува како треба да се конструираат специфични функции кога се дадени многу вистински типови или вредности. Процесот на дизајнирање се нарекува инстанција на шаблонот. Се извршува имплицитно, како несакан ефект на повикот

Од книгата на авторот

Од книгата на авторот

10.11. Пример за шаблон за функции Овој дел дава пример што покажува како може да се дефинираат и користат шаблоните за функции. Ова го дефинира шаблонот sort(), кој потоа се користи за сортирање на елементите на низата. Самата низа е претставена со шаблонот на класата Array (види

Од книгата на авторот

16.1. Дефинирање на шаблон за класа Да речеме дека треба да дефинираме класа која поддржува механизам за редици. Редот е структура на податоци за складирање на збирка на објекти; се ставаат на крајот од редот и се вадат од почеток. Опишано е однесувањето на редот

Функцијата за шаблон дефинира општ сет на операции што ќе се применуваат на различни типови податоци. Користејќи го овој механизам, можно е да се применат некои општи алгоритми на широк опсег на податоци. Како што знаете, многу алгоритми се логично исти без оглед на типот на податоци со кои работат. На пример, алгоритмот Quicksort е ист и за низа од цели броеви и за низа од броеви со подвижна запирка. Само типот на податоци што треба да се подредат се разликува. Со креирање на генеричка функција, можете да ја дефинирате суштината на алгоритмот без оглед на типот на податоци. По ова, компајлерот автоматски го генерира точниот код за типот на податоци за кој е креирана оваа специфична имплементација на функцијата во фазата на компилација. Во суштина, кога се креира функција на шаблон, таа создава функција која автоматски може да се преоптоварува.

Функциите на шаблонот се креираат со помош на клучниот збор за шаблон. Вообичаеното значење на зборот „шема“ прилично целосно ја одразува неговата употреба во C++. Шаблонот се користи за креирање на скелетот на функцијата, оставајќи ги деталите за имплементацијата на компајлерот. Општата форма на функцијата шаблон е како што следува:

шаблон Враќање_тип на функцијата_име (листа на параметри)
{
// функционално тело
}

Овде ptype е параметар за тип, „местодржач“ за името на типот на податоци што се користи од функцијата. Овој тип параметар може да се користи во дефиниција на функција. Сепак, ова е само „држач за место“ што автоматски ќе биде заменет од компајлерот со вистинскиот тип на податоци кога ќе се креира одредена верзија на функцијата.

Подолу е краток пример кој создава шаблон функција која има два параметри. Оваа функција ги менува вредностите на овие параметри меѓу себе. Бидејќи општиот процес на размена на вредности помеѓу две променливи не зависи од нивниот тип, тој природно може да се имплементира со помош на функцијата шаблон.

// пример шаблон за функција
#вклучи
// шаблон за функција
шаблон размена на празнини (X &a, X &b)
{
X температура;
temp = a;
a = b;
b = температура;
}
int main()
{
int i=10, j = 20;
плови x=10,1, y= 23,3;
char a="x", b="z";
коут<< "Original i, j: " << i << " " << j << endl;
коут<< "Original x, y: " << x << " " << у << endl;
коут<< "Original a, b: " << a << " " << b << endl;
swap(i, j); // размена на цели броеви
swap (x, y); // размена на реални вредности
замена (а, б); // размена на знаци
коут<< "Swapped i, j: " << i << " " << j << endl;
коут<< "Swapped x, y: " << x << " " << у << endl;
коут<< "Swapped a, b: " << a << " " << b << endl;
врати 0;
}

Ајде внимателно да ја разгледаме оваа програма. Линија

Шаблон размена на празнини (X &a, X &b)

Му укажува на компајлерот дека се генерира шаблон. Овде X е шаблонот за тип кој се користи како параметар за тип. Следно доаѓа декларацијата на функцијата swap(), користејќи податочен тип X за оние параметри кои ќе разменуваат вредности. Во функцијата main(), се повикува функцијата swap() со три различни типови на податоци кои се доставуваат до неа: цели броеви, броеви со подвижна запирка и знаци. Бидејќи функцијата swap() е шаблон функција, компајлерот автоматски ќе создаде три различни верзии на функцијата swap() - една за работа со цели броеви, друга за работа со броеви со подвижна запирка и на крајот трета за работа со променливи на знаци.

Лекција 29. Користење на шаблони за функции

Кога креирате функции, понекогаш се појавуваат ситуации кога две функции вршат иста обработка, но работат на различни типови на податоци (на пример, едната користи параметри од типот int, а другата од типот float). Веќе знаете од Лекцијата 13 дека со користење на преоптоварување на функциите, можете да го користите истото име за функции кои вршат различни работи и имаат различни типови на параметри. Меѓутоа, ако функциите враќаат вредности од различни типови, треба да користите уникатни имиња за нив (види белешка во Лекција 13). На пример, да претпоставиме дека имате функција со име max која враќа максимум од две цели броеви. Ако подоцна ви треба слична функција која враќа максимум две вредности со подвижна запирка, треба да дефинирате друга функција, како што е fmax. Во ова упатство, ќе научите како да користите C++ шаблони за брзо креирање функции кои враќаат вредности од различни типови. До крајот на оваа лекција, ќе ги совладате следните основни концепти:

    Шаблонот дефинира збир на изјави што вашите програми подоцна можат да ги користат за да создадат повеќе функции.

    Програмите често користат шаблони за функции за брзо дефинирање на повеќе функции кои користат исти изјави за да работат на различни типови параметри или имаат различни типови на враќање.

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

    Откако вашата програма ќе дефинира шаблон за функција, тогаш може да создаде одредена функција со користење на тој шаблон за да наведете прототип што го вклучува името на шаблонот, повратната вредност на функцијата и типовите на параметри.

    За време на процесот на компајлирање, компајлерот C++ ќе креира функции во вашата програма користејќи ги типовите наведени во прототиповите на функцијата што го повикуваат името на шаблонот.

Шаблони за функции имаат единствена синтакса што можеби не е јасна на прв поглед. Сепак, откако ќе креирате еден или два шаблони, ќе откриете дека тие се всушност многу лесни за употреба.

КРЕИРАЈ ЕДНОСТАВЕН шаблон за ФУНКЦИЈА

Шаблон за функција дефинира функција независна од типот. Со таков образец, вашите програми потоа можат да дефинираат специфични функции со потребните типови. На пример, следниот шаблон е дефиниран за функцијата со име max која враќа поголема од две вредности:

шаблон T max(T a, T b)

(ако (а > б) врати (а); инаку врати (б); )

Буквата Т во овој случај претставува општ тип на шема. Откако ќе дефинирате шаблон во вашата програма, прогласувате прототипови на функции за секој тип што ви треба. Во случајот со шаблонот tach, следните прототипови создаваат функции од типот float и int.

float max(float, float); int max(int, int);

Кога компајлерот C++ ќе се сретне со овие прототипови, ќе го замени шаблонот тип T со типот што ќе го наведете при конструирањето на функцијата. Во случај на типот float, функцијата макс по замената ќе ја има следната форма:

шаблон T max(T a, T b)

(ако (а > б) врати (а) ; друго врати (б); )

плови макс (плови а, плови б)

(ако (а > б) врати (а) ; друго врати (б); )

Следната програма MAX_TEMP.CPP ја користи макс шемата за да создаде функција од типот int и float.

#вклучи

шаблон T max(T a, T b)

(ако (а > б) врати (а); инаку врати (б); )

float max(float, float);

int max(int, int);

(изрази<< "Максимум 100 и 200 равен " << max(100, 200) << endl; cout << "Максимум 5.4321 и 1.2345 равен " << max(5.4321, 1.2345) << endl; }

За време на компилацијата, компајлерот C++ автоматски генерира изјави за да конструира една функција која работи на типот int и втора функција која работи на типот float. Бидејќи компајлерот C++ управува со операторите што одговараат на функциите што ги креирате користејќи шаблони, тој ви овозможува да ги користите истите имиња за функции кои враќаат вредности од различни типови. Не можете да го направите ова користејќи само преоптоварување на функциите, како што беше дискутирано во Лекцијата 13.

Користење на шаблони за функции

Како што вашите програми стануваат посложени, може да има моменти кога ќе ви требаат слични функции кои ги извршуваат истите операции, но на различни типови податоци. Шаблон за функции им овозможува на вашите програми да дефинираат генеричка или независна од типот функција. Кога програмата треба да користи функција за одреден тип, како што се int или float, таа одредува прототип на функција што го користи името на шаблонот за функција и типовите враќање и параметри. За време на компилацијата, C++ ќе ја создаде соодветната функција. Со креирање на шаблони, го намалувате бројот на функции што треба сами да ги кодирате, а вашите програми можат да го користат истото име за функции кои вршат одредена операција, без оглед на повратната вредност на функцијата и типовите на параметри.

Шаблони КОИ КОРИСТАТ ПОВЕЌЕ ВИДОВИ

Претходната дефиниција на шаблонот за функцијата max користеше еден генерички тип, T. Многу често, треба да наведете повеќе типови во шаблон за функции. На пример, следните изјави создаваат шаблон за функцијата show_array, која ги прикажува елементите на низата. Шаблонот користи тип T за да го означи типот на низата и тип T1 за да го означи типот на параметарот count:

шаблон

< count; index++) cout << array << " "; cout << endl; }

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

void show_array (int *, int); void show_array (float *, непотпишан);

Следната програма SHOW_TEM.CPP користи шаблон за креирање функции кои излегуваат низи од типот int и тип float.

#вклучи

шаблон void show_array (T * низа, T1 броење)

( Индекс Т1; за (индекс =0; индекс< count; index++) cout << array “ " "; cout << endl; }

void show_array (int *, int);

void show_array (float *, непотпишан);

( int страници = ( 100, 200, 300, 400, 500); float цени H = ( 10.05, 20.10, 30.15); show_array (страници, 5); show_array (цени, 3); )

Шаблони и повеќе видови

Како што функционалните шаблони стануваат покомплексни, тие можат да поддржуваат повеќе типови. На пример, вашата програма може да создаде шаблон за функцијата наречена array_sort која ги сортира елементите на низата. Во овој случај, функцијата може да користи два параметри: првиот, што одговара на низата, а вториот, што одговара на бројот на елементи од низата. Ако програмата очекува дека низата никогаш нема да содржи повеќе од 32767 вредности, може да го користи типот int за параметарот за големина на низата. Како и да е, погенеричка шема може да и даде на програмата можност да одреди свој тип за овој параметар, како што е прикажано подолу:

шаблон Т , класа T1> void array_sort (T низа, T1 елементи)

(// оператори)

Користејќи го шаблонот array_sort, програмата може да креира функции кои сортираат мали float низи (помалку од 128 елементи) и многу големи int низи користејќи ги следните прототипови:

void array_sort (float, char); void array_sort (int, long);

ШТО ТРЕБА ДА ЗНАЕТЕ

Како што веќе знаете, користењето шаблони за функции го намалува програмскиот напор со тоа што му дозволува на компајлерот C++ да генерира изјави за функции кои се разликуваат само во нивните типови и параметри за враќање. Во Лекција 30, ќе научите како да користите шаблони за да креирате класи независни од типот или генерички. Пред да ја проучувате лекцијата 30, проверете дали сте ги совладале следните основни концепти:

      Шаблони за функции ви дозволуваат да декларирате функции независни од типот или генерички.

      Кога вашата програма треба да користи функција со одредени типови податоци, таа мора да наведе прототип на функција што ги специфицира потребните типови.

      Кога компајлерот C++ ќе наиде на таков прототип на функција, тој ќе создаде изјави што одговараат на таа функција, заменувајќи ги потребните типови.

      Вашите програми мора да креираат шаблони за вообичаени функции кои работат на различни типови. Со други зборови, ако користите само еден тип со функција, нема потреба да користите шаблон.

      Ако функцијата бара повеќе типови, шаблонот едноставно му доделува на секој тип единствен идентификатор, како што се T, T1 и T2. Подоцна во процесот на компилација, компајлерот C++ правилно ќе ги додели типовите што сте ги навеле во прототипот на функцијата.

Сакав да напишам текст за секакви кул структури на податоци, а потоа се покажа дека сè уште не сме испитувале неколку многу важни карактеристики на C++. Шаблоните се еден од нив.

Шаблоните се многу моќна алатка. Функциите и класите на шаблоните можат многу да го поедностават животот на програмерот и да заштедат огромно количество време, напор и нерви. Ако мислите дека шаблоните не се многу значајна тема за проучување, знајте дека грешите.

Функции на шаблон

Едноставен пример за функција на шаблон:

C++ кодВнесете квадрат (Тип a) ( Тип b; b = a*a; врати b; ) int x = 5; int i; i = квадрат (5); плови y = 0,5; плови f; f = квадрат (y);

Ако ги креиравме функциите на старомоден начин, тогаш ќе треба да напишеме две различни функции: за типот int и за типот float. И ако ви требаше истата функција користејќи други типови, ќе треба да ја напишете повторно. Користејќи шаблони, можете да се ограничите на само еден пример од функцијата, оставајќи ја целата валкана работа на компајлерот.

Наместо да користи одреден тип, функцијата користи параметарски тип (или, со други зборови, аргумент за шаблон). Овде параметарскиот тип го нареков идентификатор Тип. Овој идентификатор се појавува три пати во функцијата: повратната вредност, аргументот на функцијата и дефиницијата на променливата s. Тоа е, Type се користи како и секој обичен тип.

Но, за да работи кодот, треба да ја додадете следнава линија пред функцијата (покажав неколку опции за синтакса, сите тие работат):

C++ кодшаблон Напишете квадрат (Тип а) шаблон < class Type >Напишете квадрат (Тип а) шаблон< class Type >Напишете квадрат (тип а)

Значи, на функцијата мора да ѝ претходи шаблонот за клучни зборови, а во аголни загради мора да го наведете името на параметарскиот тип со класата на клучниот збор. Наместо клучниот збор класа, можете да користите тип - генерално, нема разлика.

Идентификаторот за параметарски тип, исто така, може да биде што било. Често ќе ги користиме овие: TypeA, TypeB, Datatype, T.

Важна забелешка: Функциите на шаблоните мора да имаат аргумент за да може компајлерот да одреди кој тип да го користи.

Можете да користите неколку параметарски типови во шаблоните, а секако можете да измешате параметарски типови со стандардни (само треба да се грижите за точниот тип кастинг). Ќе дадам пример кој користи два параметарски типа TypeA, TypeB и основниот тип int:

C++ кодшаблон Пример_функција TypeB (TypeA a, TypeB b) ( int x = 5; b = a + x; враќање b; )

Но, функциите на шаблоните не се најинтересното нешто што ќе го разгледаме денес.

Шаблонски часови

Општо земено, класите на шаблоните се креираат на ист начин како и функциите на шаблоните - шаблонот за клучни зборови се пишува пред името на класата. Ајде да ги погледнеме класите на шаблони користејќи стек како пример:

C++ кодшаблон класа стек ( приватно: int top; Тип s; јавно: стек (): top(0) () void push(Type var) ( top++; s = var; ) Тип pop(); ); шаблон Напишете stack::pop() ( Type var = s; top--; return var; ) Овде дефинираме

сподели куп од десет елементи. Овие елементи можат да бидат од било кој тип, повеќе за тоа подолу.

Единственото нешто на што сакам да ви го привлечам вниманието е дефиницијата на функциите push и pop. Функцијата push е дефинирана внатре во класата, а функцијата поп е дефинирана надвор од неа. За сите функции декларирани надвор од класата, мора да се наведе клучниот збор за шаблонот. Изразот пред името на функцијата е ист како оној пред името на класата.

Сега да видиме како да работиме со класи на шаблони:

C++ кодмагацинот s1; магацинот s2; s1.push(3); s1.push(2); s1.pop(); s2.push(0.5);

Кога креирате објект, по името на класата треба да ставите аголни загради во кои ќе го означите саканиот тип. По ова, објектите се користат како што сме навикнати.

Класите на шаблони имаат една неверојатна карактеристика - покрај стандардните типови, тие можат да работат и со сопствени. Ајде да погледнеме мал пример. За да го направите ова, ајде да дефинираме едноставна класа на воин:

C++ кодкласа воин (јавно: int здравје; воин () : здравје(0) () ); магацинот s; воин w1; воин w2; воин w3; s.push(w1); s.push(w3); s.pop(); s.push(w2);

Видете, сега можете да ставите променливи тип воин на стекови!!! Можеби нема да ми верувате, но ова е многу кул! Можете да видите колку е убаво ова кога создаваме графикони и дрвја врз основа на списоци.

Тоа е сè според шаблоните засега. Подоцна ќе разгледаме посложени случаи на користење класи на шаблони.

Специјализацијата на шаблоните е една од „комплексните“ карактеристики на јазикот C++ и главно се користи при креирање библиотеки. За жал, некои од карактеристиките на специјализацијата на шаблоните не се многу добро опфатени во популарните книги на овој јазик. Згора на тоа, дури и 53-те страници од официјалниот ISO јазичен стандард посветени на шаблони опишуваат интересни детали на хаотичен начин, оставајќи многу да „погодите сами - очигледно е“. Под резот, се обидов јасно да ги наведам основните принципи на специјализацијата на шаблоните и да покажам како овие принципи можат да се користат при конструирање магични магии.

Здраво свет

Како сме навикнати да користиме шаблони? Го користиме клучниот збор за шаблон, потоа имињата во аголни загради параметри на шаблонот, проследено со тип и име. За параметрите, тие исто така покажуваат што е тоа: тип (име на тип) или вредност (на пример, int). Типот на самиот шаблон може да биде класа (класа), структура (структура - всушност и класа) или функција (bool foo() и така натаму. На пример, наједноставната класа на шаблон „А“ може да се дефинира вака:

По некое време, ќе сакаме нашата класа да работи исто за сите типови, но различно за некои незгодни како int. Глупо прашање, ајде да напишеме специјализација: изгледа исто како реклама но параметриние не го означуваме шаблонот во аголни загради, наместо тоа, означуваме специфични аргументишаблон по неговото име:

Шаблон<>класа А< int >(); // тука int е аргументот на шаблонот
Готово, можете да напишете методи и полиња на специјална имплементација за int. Оваа специјализација обично се нарекува полн(целосна специјализација или експлицитна специјализација). За повеќето практични задачи, не е потребно повеќе. И ако е потребно, тогаш ...

Прилагоден шаблон е нов шаблон

Ако внимателно го прочитате ISO C++ стандардот, ќе најдете интересна изјава: со создавање на специјализирана класа на шаблони, создаваме нова класа на шаблони(14.5.4.3). Што ни дава ова? Специјализирана класа на шаблони може да содржи методи, полиња или декларации за типови што не се наоѓаат во класата на шаблони што ја специјализираме. Удобно е кога ви треба метод за класа на шаблон да работи само за одредена специјализација - доволно е да го декларирате методот само во оваа специјализација, компајлерот ќе го стори останатото:

Специјализираниот шаблон може да има свои параметри на шаблонот

Ѓаволот, како што знаеме, е во деталите. Фактот дека специјализираната класа на шаблони е сосема нова и посебна класа е секако интересен, но има малку магија во неа. А магијата лежи во мала последица - ако ова е посебна класа на шаблони, тогаш може да има посебни кои на никаков начин не се поврзани со неспецијализираната класа на шаблони параметри(параметрите се она што е по шаблонот во аголни загради). На пример, вака:

Шаблон< typename S, typename U >класа А< int > {};
Точно, ова е токму кодот на компајлерот нема да се состави- не ги користиме новите параметри на шаблоните S и U, што е забрането за специјализирана класа на шаблони (а специјализираниот компајлер разбира дека ова е класа затоа што го има истото име „А“ како веќе декларирана класа на шаблони). Компајлерот дури и ќе каже посебна грешка: „експлицитната специјализација користи синтакса на делумна специјализација, користете шаблон<>наместо тоа“. Совети дека ако немате што да кажете, тогаш треба да користите шаблон<>и не се покажувај. Тогаш зошто можете да користите нови параметри во специјализирана класа на шаблони? Одговорот е чуден - за да прашам аргументиспецијализации (аргументи се она што е по името на класата во аголни загради). Односно, со специјализирање на шаблонска класа, наместо едноставна и разбирлива int, можеме да ја специјализираме преку нови параметри:

Шаблон< typename S, typename U >класа А< std::map< S, U > > {};
Таков чуден запис ќе се состави. И кога се користи добиената класа на шаблон со std::map, ќе се користи специјализација, каде што клучниот тип на std::map ќе биде достапен како параметар на новиот шаблон S, а типот на вредност на std::map како У.

Оваа специјализација на шаблон, во која е наведена нова листа на параметри и преку овие параметри се специфицираат аргументи за специјализацијата, се нарекува делумна специјализација(делумна специјализација). Зошто „делумно“? Очигледно затоа што првично беше наменета како синтакса за специјализирање на шаблон не за сите аргументи. Пример каде што класата шаблон со два параметри е специјализирана само за еден од нив (специјализацијата ќе работи кога првиот аргумент, T, е наведен како int. Во овој случај, вториот аргумент може да биде што било - за ова, нов параметар U е воведени во делумната специјализација и наведени во списокот аргументи за специјализација):

Шаблон< typename T, typename S >класа Б(); шаблон< typename U >класа Б< int, U > {};

Магичните последици од делумната специјализација

Двете својства на специјализацијата на шаблоните опишани погоре имаат голем број интересни последици. На пример, кога користите делумна специјализација, можете, со воведување на нови параметри на шаблонот и опишување специјализирани аргументи преку нив, да ги разделите сложените типови на едноставни. Во примерот подолу, специјализираната класа на шаблон А ќе се користи ако аргументот на шаблонот е тип на покажувач на функција. Во овој случај, преку новите параметри на шаблонот S и U, можете да го добиете типот на повратната вредност на оваа функција и видот на нејзиниот аргумент:

Шаблон< typename S, typename U >класа А< S(*)(U) > {};
И ако декларирате typedef или static const int во специјализиран шаблон (искористувајќи го фактот дека ова е нов шаблон), тогаш можете да го користите за да ги извлечете потребните информации од типот. На пример, користиме шаблонска класа за складирање на објекти и сакаме да ја добиеме големината на предадениот објект или 0 ако е покажувач. Во два реда:

Шаблон< typename T >struct Get ( const static int Size = sizeof(T); ); шаблон< typename S >struct Get< S* >( const static int Size = 0; ); Добијте< int >::Големина // на пример, 4 Земете< int* >::Големина // 0 - го најде покажувачот :)
Магијата од овој тип се користи главно во библиотеките: stl, boost, loki и така натаму. Се разбира, користењето такви трикови во програмирањето на високо ниво е малку незгодно - мислам дека сите се сеќаваат на конструкцијата за добивање големина на низа :). Но, во библиотеките, делумната специјализација го прави релативно лесно спроведувањето на делегати, настани, сложени контејнери и други понекогаш многу неопходни и корисни работи.

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

Ажурирање: Ветено продолжение