Sablonok

C++-ban függvény-, illetve osztálysablonok (ún. templatek) létrehozására van lehetoségünk. Ezek konstanssal, ill. típussal paramáterezhetok. Lényeges különbség más programnyelvekhez képest az explicit példányosítás szükségtelensége, valamint az argumentumok megszoríthatóságának hiánya.

A template argumentumok néhány jellemzoben eltérnek a hagyományos (függvény) argumentumoktól:

A fenti jellemzoktol eltekintve a template argumentumok mindenben a függvényargumentumokra hasonlítanak, azaz:

Templatek deklarálása az alábbi szintakszissal történik:

template< template arg. list > decl

Ahol decl a hagyományos (függvény vagy osztály) deklarációnak felel meg, de használhatja a template argumentumokat is. A template argumentum listát a szokott szintakszissal kell deklarálni, kivéve a típus argumentumokat, amelyekre a class vagy a typename kulcszó használható.

Template függvények

Deklarált template függvények használatához szükségtelen példányosítani az adott függvényt (ez automatikusan megtörténik), sot, a legtöbb esetben azt sem kell explicit módon megjelölni, hogy milyen argumentumokkal meghatározott template függvénypéldányt akarunk meghívni. Erre szolgál az ún. template argumentum dedukció. Ennek elofeltétele, hogy minden template argumentumnak legalább egyszer szerepelnie kell a függvény hívási szignatúrájának maradékában is, vagyis nem csak a template argumentumok között. Ha ez a feltétel teljesül, akkor a fordító az átadott paraméterek típusából értékeli ki a template argumentumokat.

Fontos megjegyezni, hogy ennél a kiértékelésnél a fordító nem végez semmilyen konverziót a konkrét argumentumokon, és ha enélkül nem tud megfelelo szignatúrájú függvénypéldányt dedukálni, akkor fordítási hibát generál. Ilyen esetben lehetoségünk van a template argumentumok explicit megadására, az alábbi szintakszissal:

template<typename T> T max( T a, T b );
// ...
max<int>( 0.1, 0 );		// == (int)0
max<double>( 0.1, 0 );		// == (double)0.1

Amennyiben mégis szükséges az explicit példányosítás (pl. könyvtárszerkesztésnél), elegendo leírni a függvénypéldány nevét, vagyis:

extern max<int>( int a, int b );
// vagy
extern max( int a, int b );

Template osztályok

A template osztályok definíciója két részre bontható. Egyrészt tartalmaz egy adatszerkezet definíciót, amely önmagában is függhet a template argumentumoktól. Másrészt ehhez az adatszerkezethez template függvényeket rendel, az alábbi módon:

template< typename myclass, class templ. arg. list >
type myclass_myfunc( myclass * const this, func. arg. list )

Osztálytemplate-k deklarálásakor elég egyszer, a deklaráció elején megadni a template argumentumlistát, de ha a deklaráció során bármikor szerepeltetni akarjuk az osztályt, template osztályról lévén szó annak argumentumait is meg kell adnunk. Ez alól egyetlen kivétel a konstruktorok illetve a destruktorok deklarálása, hiszen ott egyértelmu hogy melyik osztályhoz tartozó deklarációról van szó. Az osztálytemplate-k definiálásakor természetesen minden tagnál külön deklarálnunk kell a template argumentumlistát is, valamit az osztály minden hivatkozásánál meg kell adni az argumentum listát is (ez alól ismételten a konstruktorok definiálása a kivétel, a fenti okok miatt).

Ez alapján például egy string template osztály deklarációja és definíciója a következoképpen nézhetne ki:

template<typename base>
class string
{
public:
	string( void );			// itt nem kell megadni az argumentumot
	~string( void );

	string<base> &operator=( const string<base> &other ); // itt viszont már kötelezo
};
// definícióknál pedig minden szimbólumra újra kell deklarálni a formális argumentumokat
// ne feledjuk, hogy tulajdonképpen közönséges tempate függvényeket deklarálunk implicit
// this paraméterrel
template<typename base>
string<base>::string( void ) { ... };	// itt elég csak egyszer megadni az argumentumokat
// itt viszont meg kell adni mindenhol az argumentumokat
template<typename base>
string<base> &string<base>::operator=( const string<base> &other ) {};

Template tagfüggvények

Láthattuk tehát, hogy a template osztályok tagfüggvényei egyszeru template függvények (ugyanúgy, ahogy az osztályok tagfüggvényei is egyszeru függvények). Lehetoségünk van azonban, template tagfüggvények deklarálására is. Ez tulajdonképpen nem jelent mást, mint hogy egy template osztály tagfüggvényének template argumentumlistáját más, extra argumentumokkal bovítjük. Ennek szintakszisa nagyon következetes. Osztályon belüli template-t ugyanúgy deklarálunk mint osztályon kívül, csak azt jegyezzük meg, hogy ennek a template-nek már eleve vannak template argumentumai, amiket az osztáltól örökölt.

Ez alapján például egy mátrix osztály szorzás muveletét az alábbi módon lehetne deklarálni:

template<int x, int y> class matrix 
{
	template<int z> matrix<x,z> operator*( const matrix<y,z> &other ) const;
// ...
};
// ennek a definíciója valahogy így nézhet ki:
template<int x, int y, int z>
matrix<x,y> matrix<x,y>::operator*( const matrix<y,z> &other ) const {};

Célszeru megjegyezni, hogy a template tagfüggvényeket számos C++ fordító nem megfeleloképpen kezeli, legtöbbször az argumnetumdedukció okoz az ilyen fordítóknak nehézségeket.

Template specializáció

Gyakran elofordul, hogy meghatározott muveletek, amelyek sablonokkal írhatók le a legtöbb adattípusra, egy bizonyos adattípusra kivételes módon végzendo. Ilyenkor használható a template specializáció. Ez nem jelent mást, mint egy adott paraméterezésu template függvény definíciójának konkrét megadását.

Ennek szintakszisa az alábbi:

template<>
string<char> &string<char>::operator=( const string<char> &other )
{
	return( strcpy( mystr, other.mystr ), *this );
}

Ha a fenti példához az elozoekben már deklarált string osztályt vesszük figyelembe, akkor egy olyan template osztályt kapunk, amelynek a char típussal való paraméterezése esetén az értékadás operátorában a könyvtári strcpy függvényt használjuk. Mind a char paraméterezésu osztály többi muveletére, mind pedig a más paraméterezésu osztályok összes muveletére az elozoekben adott osztálydeklaráció a mérvadó.

Elonyök és hátrányok

A template-k használata az alábbi vitathatatlan elonyökkel jár:

Sajnos mindemellett számolnunk kell a template-használat hátrányaival is: