Šablony funkcí II
C++ 11

image_printTisk

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 pravidla pro přetěžování šablon a klasických funkcí.

Výklad zahájíme o nových typech parametrů šablon. Kromě datových typu reprezentovaných klíčovým slovem typename, lze do parametrů šablon také uvádět i celočíselné datové typy. Proto tam můžeme uvést i datový typ int, long, aj. Ukažme si vše na příkladu.

#include <iostream>
using namespace std;

template<int SIZE, typename T>
T soucet(T* array) {
    T sum = 0;
    for(int i = 0; i < SIZE; i++) {
        sum += array[i];
    }
    return sum;
}

const int MAX_SIZE = 10;
double pole[MAX_SIZE] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.1 };

int main() {
    cout << "Soucet je " << soucet<MAX_SIZE>(pole) << endl;
    return 0;
}

Na příkladu je vidět šablona funkce soucet pro sečtení hodnot pole konstantní délky. V šabloně jsou dva parametry. Prvním z nich je délka pole vyjádřená pomocí typu int a po té následuje datový typ pole reprezentovaným parametrem T. Ve funkci main pak je proveden součet pole typu double o počtu položek vyjádřeného konstantou MAX_SIZE. U volání funkce je délka pole uvedena explicitně, ale vlastní datový typ pole je odvozen z argumentu volání funkce.

Nyní se chvíli zastavme u přetěžování šablon funkcí. Platí pro ně v podstatě analogická pravidla jako pro přetěžování funkcí klasických, kdy se překladač snaží nalézt co nejlepší šablonu funkce, která by vyhovovala seznamu argumentů uvedených v jejím volání, či jinými slovy instancování. Ukažme si vše na příkladu, kde přetížíme funkci soucet o další dvě nové funkce, které budou sčítat dvourozměrná a trojrozměrná pole. Pro jednoduchost příkladu bude platit omezení, že délka všech rozměrů musí být stejná.

#include <iostream>
using namespace std;

// Sčítá jednorozměrné pole
template<int SIZE, typename T>
T soucet(T* array) {
    T sum = 0;
    for(int i = 0; i < SIZE; i++) {
        sum += array[i];
    }
    return sum;
}

// Sčítá dvourozměrné pole
template<int SIZE, typename T>
T soucet(T (*array)[SIZE]) {
    T sum = 0;
    for(int i = 0; i < SIZE; i++) {
        sum += soucet<SIZE>(*(array + i));
    }
    return sum;
}

// Sčítá trojrozměrné pole
template<int SIZE, typename T>
T soucet(T (*array)[SIZE][SIZE]) {
    T sum = 0;
    for(int i = 0; i < SIZE; i++) {
        sum += soucet<SIZE>(*(array + i));
    }
    return sum;
}

const int MAX_SIZE = 3;

double pole[MAX_SIZE] = { 1.1, 2.2, 3.3 };

double pole2D[MAX_SIZE][MAX_SIZE] = {
    { 1.1, 2.2, 3.3 },
    { 1.1, 2.2, 3.3 },
    { 1.1, 2.2, 3.3 }
};

double pole3D[MAX_SIZE][MAX_SIZE][MAX_SIZE] = {
    { { 1.1, 2.2, 3.3 }, { 1.1, 2.2, 3.3 }, { 1.1, 2.2, 3.3 } },
    { { 1.1, 2.2, 3.3 }, { 1.1, 2.2, 3.3 }, { 1.1, 2.2, 3.3 } },
    { { 1.1, 2.2, 3.3 }, { 1.1, 2.2, 3.3 }, { 1.1, 2.2, 3.3 } } 
};

int main() {
    cout << "Soucet 1D pole je " << soucet<MAX_SIZE>(pole) << endl;
    cout << "Soucet 2D pole je " << soucet<MAX_SIZE>(pole2D) << endl;
    cout << "Soucet 3D pole je " << soucet<MAX_SIZE>(pole3D) << endl;
    return 0;
}

Na závěr se stručně zmíníme o vztahu mezi klasickými funkcemi a šablonami při jejich přetěžování. V podstatě zjednodušeně řečeno, překladač postupuje dle následující hierarchie:

  1. První překladač hledá, zda existuje v modulu deklarovaná klasická funkce, která by vyhovovala parametrům volání.
  2. Pokud není nalezena, hledá se nějaká vhodná šablona, ze které by příslušná funkce šla vygenerovat.
  3. Pokud ani toho není dosaženo, ohlásí se chyba překladu.

Ukažme si vše na posledním příkladu demonstrujícím prioritu klasických funkcí před jejich šablonami.

#include <cstring>
#include <iostream>
using namespace std;

template<typename T>
bool isLess(T a, T b) {
    return a < b;
}

bool isLess(const char* a, const char* b) {
    return strlen(a) < strlen(b);
}

int main() {
    cout << boolalpha;
    cout << "1 < 3: " << isLess(1, 3) << endl;
    cout << "3.14 > 2.1: " << isLess(3.14, 2.1) << endl;
    cout << "\'aaa\' < \'bbbb\': " << isLess("aaa", "bbbb") << endl;
    cout << "\'aaa\' > \'bb\': " << isLess("aaa", "bb") << endl;
    cout << "1.111 < 2.222: " << isLess(1.111, 2.222) << endl;
    return 0;
}

Shrnutí:

  • Šablony funkcí kromě datových typů uvozených klíčovým slovem typename mohou také obsahovat celočíselné typy jako int, long, apod.
  • Při přetěžování šablon funkcí platí analogická pravidla jako u funkcí klasických, kdy se překladač snaží nalézt co nejlepší shodu mezi deklarací příslušné šablony a argumenty instancování dané funkce.
  • Volání klasických funkcí má prioritu před instancováním šablon.
  • Pokud není při překladu nalezena vhodná funkce, ani její šablona, ohlásí překladač syntaktickou chybu.

 

image_printTisk
Šablony funkcí II
C++ 11
3.8 (76%) 5 hlasů

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í I 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 […]
  • Vícerozměrná pole Tento článek pojednává o vícerozměrných polích v jazyce C++. Seznámíme se s jejich významem, deklarací, inicializací a způsobem zápisu a čtení jejich hodnot. Na závěr článku bude zmíněno, […]
  • Metody vracení hodnot z funkce DO POKROČILÝCH ASI Tento článek pojednává o způsobech vracení hodnot z funkcí. Jsou to stejné způsoby, o kterých je psáno ve článku předchozím, tedy vracení hodnotou nebo vracení […]
  • Předávání a vracení polí z funkcí DO POKROČILÝCH TÉMAT Tento článek pojednává o práci s poli a funkcemi. Popisuje rozličné metody, jak předat pole jako argument funkci a také jak pole z funkce vrátit. Existují v […]
  • Pole v C++ V tomto článku si vysvětlíme nový pojem jazyka C++, a to pole nějakých hodnot. Je to jazykový konstrukt, který slouží k uchování seznamu hodnot nějakého datového typu. Je důležité zmínit, […]