Autor: Razzor
Corectari: Astan
I Functii templateAcesta este un tutorial despre functii template urmand sa fac cat de curant unul despre clase template.
1.1 Sintaxa and otherFunctile template reprezinta o familie de functii.
Ele arata ca si o functie normala cu exceptia unor elemente care le vom explica.Urmatoarea functie template returneaza maximul dintre doua valori:
Code:
template <typename T>
const T& maxim (const T& a, const T& b)
{
//Daca a<b returneaza b, altfel returneaza a
return a < b ? b : a;
}
Aceasta definitie produce o familie de functii care returneaza maximul a doua valori care sunt pasate prin intermediul parametrilor a si b.Tipul acestor parametrii este lasat liber cu un parametru template T.
Dupa cum am vazut in exemplu, parametrii template trebuie sa fie anuntati cu o syntaxa de genul :
Code:
template < lista_de_parametrii_separata_prin_virgule >
In exemplul nostru lista de parametrii continea doar un parametru si anume
typename T.Observam de asemenea semnul mai mic si mai mare, acestea au rolul de paranteze unghiulare.Observam si cuvantul cheie
typename care este folosit pentru a defini tipul parametrilor.Din motive istorice se poate folosit si
class in loc de
typename.Cuvantul cheie
typename a fost introdus relativ recent in evolutia limbajului c++.
Se prefera folosirea cuvantului
typename deoarece cuvantul
class poate induce in eroare iar intre ele nu exista practic nici o diferenta.
Urmatorul cod prezinta folosirea acestei functii template:
Code:
#include <iostream>
#include <string>
using namespace std;
//functia template
template <typename T>
const T& maxim (const T& a, const T& b)
{
return a < b ? b : a;
}
int main()
{
int i = 42;
int j = 34;
cout << "int max "<<maxim(i,j)<<endl;
double d1 = 3.4;
double d2 = -6.7;
cout << "double max " << maxim(d1,d2) <<endl;
string s1 = "ilea";
string s2 = "cristian";
cout << "string max " << maxim(s1,s2) <<endl;
return 0;
}
In acest program, functia maxim() este apelata de 3 ori.Odata pentru doua
int-uri apoi pentru doua
double-uri si apoi pentru doua
string-uri.De fiecare data maximul este determinat iar programul afiseaza urmatoarele:
Code:
int max 42
double max 3.4
string max ilea
Functiile template nu sunt compilate in entitati singulare care sa poata primi orice tip ca parametru.In schimb se genereaza entitati diferite din template pentru fiecare tip pentru care functia template este folosita.Sa luam ca exemplu prima apelare a lui maxim().
Code:
int i = 42;
int j = 34;
cout << "int max "<< maxim(i,j) << endl;
Acesti prim apel foloseste functia template cu
int ca si parametru in loc la T.Codul echivalent pentru aceasta functie este:
Code:
const int& maxim (const int& a, const int& b)
{
return a < b ? b : a;
}
Procesul de a inlocui parametrii template cu tipuri concrete se numeste
instantiere.Similar cu apelul lui maxim() pentru
int asa se instantiaza si pentru
double sau
string:
Code:
const double& maxim (const double& d1, const double& d2); {/* ... */}
const string& maxim (const string& s1, const string& s1); {/* ... */}
1.2Deducerea parametrilorCand se apeleaza o functie template ca si maxim() , pentru unele cazuri, parametrii template sunt determinati in functie de argumentele care le pasam.Daca pasam doua
int-uri parametrului T , compilatorul C++ trebuie sa concluzioneze ca T trebuie sa fie
int.De retinut faptul ca nu este permisa conversia de tip.T trebuie sa se potriveasca exact.
De exemplu:
Code:
template <typename T>
const T& maxim (const T& a, const T& b);
/* ..cod.. */
maxim(4,7) // OK: T este int pentru amandoua argumentele
maxim(4,4.2) // Eroare: primul T este int apoi al doilea este double
Putem rezolva aceasta eroare in 2 moduri:
1.Putem folosi operatorul static_cast <tip_de_conversie> (variabila_de_convertit)
Code:
maxim(static_cast<double>(4),4.2)
Astfel 4 este convertit in double ( 4.0 ) iar T este double pentru amandoua argumentele.
2.Specificam explicit tipul lui T
Code:
maxim<double>(4,4.2)
Functile template au doua tipuri de parametrii:
1.Parametrii template care sunt declarati intre paranteze unghiulare inaintea numelui functiei template.
Code:
template <typename T> //T este parametru template
2.Parametrii de apelare care sunt declarati in paranteze rotunde dupa numele functiei template
Code:
const T& maxim (const T& a, const T& b) //a si b sunt parametrii de apelare
Puteti sa aveti cat de multi parametrii template vreti.
Putem defini maxim() cu doi parametrii de apelare de doua tipuri diferite:
Code:
template <typename T1, typename T2>
T1 maxim (const T1& a, const T2& b)
{
return a < b ? b : a;
}
/* ...cod... */
maxim(4,4.2) // e ok, dar tipul primului argument defineste tipul care va fi returnat
Aceasta pare o metoda buna dar are acest exemplu are si parti proaste.Problema este ca tipul de returnare trebuie sa fie declarat.Daca folositi unul din parametrii ca si tip de returnare, argumentul celuilalt parametru va fi convertit in in tipul primului , in ciuda intentilor utilizatorului.C++ nu pune la dispozitie un mod de a specifica "cel mai puternic tip" (desi poti sa faci asa ceva cu ajutorul unor tehnici smechere de template programming care poate o sa le prezint in alt tutorial).Deci depinde de argumentul cu care se face apelarea.Maximul dintre 42 si 66.66 poate sa fie
double 66.66 sau
int 66.
Putem sa introducem un al treilea argument template pentru a defini tipul de care il va returna functia template:
Code:
template <typename T1, typename T2, typename RT>
RT maxim (const T1& a, const T2& b);
Totusi RT nu poate fi dedus.Ca o consecinta , noi trebuie sa specificam lista de argumente in mod explicit
Code:
template <typename T1, typename T2, typename RT>
RT maxim (const T1& a, const T2& b);
maxim<int,double,double>(4,4.2) //ok, dar cam aiurea
Putem sa rearanjam parametrii template pentru ca restul sa fie deduse in mod automat:
Code:
template <typename RT, typename T1, typename T2> //observati asezarea
RT maxim (const T1& a, const T2& b);
/* ... code ... */
maxim<double>(4,4.2) // ok, tipul pe care in returneaza maxim() este double
In acest exemplu , apelul maxim<
double> seteaza RT ca fiind explicit
double, dar parametri T1 si T2 sunt dedusi ca fiind
int si
double.
1.3Supraincarcarea functilor templateCa si functile normale , functile template pot fi supraincarcate.Adica poti avea diferite definitii de functii cu acelasi nume si atunci cand un numele este folosit in apelarea functiei , compilatorul c++ trebuie sa decida care din candidati(definitii) sa aleaga.Regulile folosite pentru a decide ce definitie sa fie folosita pot deveni oarecum complicate chiar si fara temaplateuri.Mai jos vom discuta despre supraincarcarea functilor template.
Code:
//maximul a doua valori int
const int& maxim (const int& a, const int& b)
{
return a < b ? b : a;
}
//maximul dintre doua valori de orice tip
template <typename T>
const T& maxim (const T& a, const T& b)
{
return a < b ? b : a;
}
//maximul dintre 3 valori de orice tip
template <typename T>
const T& maxim (const T& a, const T& b, const T& c)
{
return maxim (maxim(a,b), c);
}
int main()
{
maxim(7, 42, 68); //1 apeleaza functia template pentru 3 argumente
maxim(7.0, 42.0); //2 apeleaza maxim<double> (prin deductie de argument)
maxim('a', 'b'); //3 apeleaza maxim<char> (prin deductie de argument)
maxim(7, 42); //4 apeleaza functia nontemplate pentru doua valori int
maxim<>(7, 42); //5 apeleaza maxim<int> (prin deductie de argument)
maxim<double>(7, 42); //6 apeleaza maxim<double> (fara deductie de argument , noi i-am impus ce sa foloseasca)
maxim('a', 42.7); //7 apeleaza functia nontemplate pentru doua valori int
return 0;
}
Dupa cum vedem in exemplul de mai sus , o functie nontemplate poate sa coexiste cu functii template care au acelasi nume.Procesul de supraincarcare prefera functia nontemplate.Al patrulea apel cade sub aceasta regula.
Code:
maxim(7, 42); // amandoua valorile se incadreaza perfect in functia nontemplate
Daca templateul poate genera o functie care sa se potriveasca mai bine, compilatorul alege functia template.Acest lucru este demonstrat de al 2-lea si al 3-lea apel:
Code:
maxim(7.0, 42.0); // apeleaza maxim<double> (prin deductie de argument)
maxim('a', 'b'); // apeleaza maxim<char> (prin deductie de argument)
Este posibil sa pasam o lista fara argumente template.Aceasta sintaxa spune compilatorului ca doar o functie template poate sa rezolve acel apel dar toti toti parametrii template trebuie dedusi din tipul argumentelor cu care apelam functia.
Code:
maxim<>(7, 42) //doar functia nontemplate poate primi argumente de tip diferit
Deoarece conversia de tip nu este posibila pentru functile template, ultimul apel foloseste functia nontemplate (iar vlorile 'a' si 42,7 sunt convertite in
int)