Šablony funkcí I
C++ 11

image_printTisk

Tímto článkem si představíme nový pojem, a to je generické programování v C++. Jedná se o způsob programování, jehož základní znalost je nutná pro použití jedné z nejdůležitějších knihoven pro C++, knihovny STL. Vysvětlíme si, co je to šablona funkce, na co se používají a seznámíme se s generováním výsledných funkcí ze šablon, které se někdy nazývá “instancování šablony”.

Generické programování, nebo jinak řečeno parametrické programování, je způsob vývoje, kdy na základě “univerzálních vzorů kódu”, tedy šablon, definujeme nové uživatelské typy v podobě tříd nebo různé funkce. Co je to ale šablona? Jedná se v podstatě o jakousi “meta-funkci” nebo “meta-třídu”, jejíž parametry nejsou ani tak konkrétní hodnoty, jako spíše datové typy. Je to vzor, z kterého překladač pak generuje úplně novou specifickou funkci nebo třídu pro zadané parametry. Na co to je dobré?

Představme si základní funkci pro výměnu dvou parametrů, tedy funkci swap. Nyní již víme, že jazyk C++ má spoustu datových typů jen pro číselné hodnoty. Bylo by opravdu ztráta času neustále opisovat tuto funkci pro každý, i třeba jen číselný, datový typ znovu a znovu, když je možné napsat ji jen jednou za použití parametru, který bude daný datový typ zastupovat. A tím je právě šablona. Ukažme si vše na následujícím příkladu.

template<typename T> 
void swap(T& a, T& b) {
    T tmp = a;
    a = b;
    b = tmp;
}

Šablona funkce je uvozena klíčovým slovem template. Za tímto klíčovým slovem následuje mezi znaky < a seznam jejích parametrů . Na našem příkladu je definován parametr T uvozený klíčovým slovem typename, který naznačuje, že parametr T zastupuje datový typ. Dále je pak už definice funkce swap stejná jako úplně klasické funkce s tím rozdílem, že místo třeba konkrétního typu int uvádíme parametr šablony T.

Ukažme si nyní vše na reálném příkladu, jak lze této funkce použít pro výměnu hodnot různých typů.

#include &lt;iostream&gt;
using namespace std;

template&lt;typename T&gt; 
void swapValues(T&amp; a, T&amp; b) {
    T tmp = a;
    a = b;
    b = tmp;
}

int main() {
    int a = 1, b = 2;
    cout &lt;&lt; &quot;a = &quot; &lt;&lt; a &lt;&lt; &quot;, b = &quot; &lt;&lt; b &lt;&lt; endl;
    swapValues&lt;int&gt;(a, b);
    cout &lt;&lt; &quot;a = &quot; &lt;&lt; a &lt;&lt; &quot;, b = &quot; &lt;&lt; b &lt;&lt; endl;
    cout &lt;&lt; endl;
    
    double aa = 1.5, bb = 2.4;
    cout &lt;&lt; &quot;aa = &quot; &lt;&lt; aa &lt;&lt; &quot;, bb = &quot; &lt;&lt; bb &lt;&lt; endl;
    swapValues&lt;double&gt;(aa, bb);
    cout &lt;&lt; &quot;aa = &quot; &lt;&lt; aa &lt;&lt; &quot;, bb = &quot; &lt;&lt; bb &lt;&lt; endl;
    cout &lt;&lt; endl;
    
    string sa(&quot;SA&quot;), sb(&quot;SB&quot;);
    cout &lt;&lt; &quot;sa = &quot; &lt;&lt; sa &lt;&lt; &quot;, sb = &quot; &lt;&lt; sb &lt;&lt; endl;
    swapValues&lt;string&gt;(sa, sb);
    cout &lt;&lt; &quot;sa = &quot; &lt;&lt; sa &lt;&lt; &quot;, sb = &quot; &lt;&lt; sb &lt;&lt; endl;
    
    return 0;
}
Unable to connect to the JDoodle service.

Na příkladu je uvedena šablona funkce jménem swapValues. Jediné pro nás zajímavé je volání této funkce v hlavní funkci main. Napřed je uveden identifikátor šablony, tedy swapValues. Po té následuje datový typ, se který bude daná šablona instancována. Datový typ se zapisuje mezi znaky < a >. Nakonec jsou v kulatých závorkách uvedeny její argumenty. Na příkladu je šablona funkce instancována pro tři datové typy, a to je int, double a string. Tento způsob instancování se nazývá explicitní, a to z důvodu, že je ve volání šablony přímo vyjádřen datový typ, se kterým se má pracovat.

Existuje také ale instancování implicitní, neboli skryté či nevyjádřené, kdy se nemusí vůbec uvádět datový typ ve volání šablony funkce. To je způsobeno tím, že překladač jazyka C++ je schopen automaticky odvodit potřebný datový typ pro šablonu přímo z argumentů volané funkce. Proto bychom mohli následující příklad přepsat ve stručnější verzi takto. Viz ukázka.

#include &lt;iostream&gt;
using namespace std;

template&lt;typename T&gt; 
void swapValues(T&amp; a, T&amp; b) {
    T tmp = a;
    a = b;
    b = tmp;
}

int main() {
    double aa = 1.5, bb = 2.4;
    cout &lt;&lt; &quot;aa = &quot; &lt;&lt; aa &lt;&lt; &quot;, bb = &quot; &lt;&lt; bb &lt;&lt; endl;
    swapValues(aa, bb);
    cout &lt;&lt; &quot;aa = &quot; &lt;&lt; aa &lt;&lt; &quot;, bb = &quot; &lt;&lt; bb &lt;&lt; endl;
    cout &lt;&lt; endl;
    
    string sa(&quot;SA&quot;), sb(&quot;SB&quot;);
    cout &lt;&lt; &quot;sa = &quot; &lt;&lt; sa &lt;&lt; &quot;, sb = &quot; &lt;&lt; sb &lt;&lt; endl;
    swapValues(sa, sb);
    cout &lt;&lt; &quot;sa = &quot; &lt;&lt; sa &lt;&lt; &quot;, sb = &quot; &lt;&lt; sb &lt;&lt; endl;
    
    return 0;
}
Unable to connect to the JDoodle service.

Na tomto příkladu je vynechán datový typ ve volání šablony a je odvozen od argumentů funkce.

Na závěr je potřeba zmínit, že šablony sami o sobě nepředstavují žádný programový kód funkce. Pokud by funkce swapValues nebyla instancována, nenašli bychom po překladu ve výsledném binárním kódu žádné její instrukce procesoru. Dále je potřeba pochopit, že každé instancování šablony funkce pro nějaký seznam datových typů vytváří funkci zcela novou. Tedy například existuje zvlášť funkce swapValues pro datový typ int, jiná zase pro double nebo string. Jak se dovíme dále, u šablon datových typů, většinou tříd, vzniká instancováním zcela nový datový typ.

Shrnutí:

  • Šablony funkcí slouží primárně k implementaci algoritmů společných pro více datových typů. Vyhýbáme se tím zbytečnému opakování stejného kódu.
  • Definice šablony funkce začíná klíčovým slovem template, a dále je uveden seznam parametrů šablony mezi znaky < a >. Zatím jsme si zmínili jeden druh parametru šablony, a to datový typ, který bývá uveden klíčovým slovem typename. Dále je pak definice funkce stejná jako funkce klasické.
  • Datový typ pro šablonu musí být uvozen znaky < a >.
  • Explicitní instancování uvádí datový typ šablony přímo do volání funkce, implicitní jej odvozuje z argumentů volání.
  • Šablona funkce sama o sobě negeneruje žádný programový kód.
  • Každé instancování šablony funkce pro daný seznam parametrů generuje funkci zcela novou.
image_printTisk
Šablony funkcí I
C++ 11
Ohodnoťte tento článek

Související články

  • Šablony tříd Tak, jak lze vytvářet šablony funkcí, lze vytvářet i šablony tříd, struktur a unionů. Pomocí těchto šablon potom překladač generuje nové uživatelsky definované datové typy. Ukážeme si […]
  • Šablony funkcí II V tomto článku dokončíme výklad o šablonách funkcí. Zmíníme se o tom, že šablony mohou obsahovat kromě parametrů reprezentujících datové typy také celočíselné hodnoty a dále si představíme […]
  • Ukazatele na pole V tomto článku si probereme ukazatele na pole. Seznámíme se nejen s ukazateli na pole jednorozměrné, ale i na složitější případ, tedy pole vícerozměrná. Vše si zase samozřejmě uvedeme na […]
  • Formátování textů na textové konzoli V tomto článku si popíšeme, jak provádět formátovaný výstup na textovou konzoli. Výše uvedené způsoby formátování výstupu lze ale použít, jak se dále dovíme, i při zápisu do souboru nebo […]
  • Komentáře Tento článek pojednává o způsobu zápisu komentářů ve zdrojových kódech jazyka C++. Budou popsány oba druhy komentářů, tedy jednořádkové i jejich víceřádková varianta. Použití […]
  • Obsluha chyb pomocí výjimek Tento článek je článkem úvodním tematice obsluhy chyb v jazyce C++. V tomto článku si představíme motivaci zavedení výjimek jazyka C++ jako aparátu pro detekci a zpracování chyb. Dále […]