Szablony funkcji
Szablony funkcji są sposobem na stworzenie funkcji, która może przyjmować argumenty dowolnych typów.
Przykładowo można stworzyć funkcje, która mnoży dwie liczby:
int pomnoz (int a, int b)
{
return a * b;
}
Funkcja taka działa poprawnie dla argumentów typu int, gdy wyniknie potrzeba użycia jej dla typu float trzeba będzie ją całą skopiować i zapisać w postaci:
float pomnoz (float a, float b)
{
return a * b;
}
Jak wiadomo w C++ może istnieć wiele funkcji o tej samej nazwie, różniących się tylko parametrami lub zwracanym typem. Więcej na ten temat w artykule Funkcje.
Potem skopiujemy ją jeszcze kilkakrotnie dla kolejnych typów które będą nam potrzebne, może będzie to unsigned int, char, double itp.
Rozwiązanie to jest mało eleganckie. Ponadto stwarza problemy - jeżeli w pierwszej funkcji wystąpi błąd trzeba będzie go poprawić we wszystkich jej kopiach, lepiej było by gdyby można było zrobić to tylko raz.
Z pomocą przychodzą szablony funkcji.
template <class Typ>
Typ pomnoz (Typ a, Typ b)
{
return a * b;
}
Taki zapis oznacza, że nie tworzymy funkcji, tylko szablon. Z takiego szablonu będziemy tworzyć funkcje w obrębie programu zastępując słowo Typ pożądanym typem zmiennej.
Słowo kluczowe class przed nazwą parametru szablonu (w tym przypadku Typ) sugeruje, że szablony mogą, a nawet powinny, przyjmować jako argumenty typy zdefiniowane przez użytkownika (Klasy). Ten przykład jednak opiera się na typach wbudowanych dla ułatwienia zrozumienia idei szablonów.
#include <iostream>
using namespace std;
template <class Typ>
Typ pomnoz (Typ a, Typ b)
{
return a * b;
}
int main()
{
float fA = 0.3;
float fB = 0.4;
int iA = 2;
int iB = 4;
cout << "Wynik mnożenia liczb typu float: " << pomnoz<float>(fA,fB) << endl;
cout << "Wynik mnożenia liczb typu int: " << pomnoz<int>(iA,iB) << endl;
return 0;
}
Proszę zwrócić uwagę na wywołanie funkcji (a właściwie szablonu) pomnoz.
pomnoz<float>(fA,fB)
Oznacza to "zamień słówko Typ w moim szablonie na float" i skutkuje wytworzeniem takiej funkcji:
float pomnoz (float a, float b)
{
return a * b;
}
Szablony mogą posiadać też więcej niż jeden argument:
#include <iostream>
using namespace std;
template <class TypPrzyjety, class TypZwracany>
TypZwracany rzutowanie (TypPrzyjety A)
{
return (TypZwracany) A;
}
int main()
{
float fA = 3.3;
int iA = 0;
iA = rzutowanie<float,int>(fA);
cout << iA; // wyświetli 3
return 0;
}
To niekoniecznie wada.
Bo programista sam sprawdza tam, gdzie uważa to za stosowne - zysk na szybkości; zresztą w Pascalu też można wyłączyć sprawdzanie zakresów (Range Checking)
Zagnieżdżanie funkcji w funkcji w Pascalu tylko spowalnia wykonywanie programu. Zresztą to nie jest jakieś dotkliwe ograniczenie.
Ale w C++ masz klasę std::string ;>
IMHO jest to język wysokiego poziomu, ale te podziały są "umowne" - zależy jak na co patrzeć ;)
W Pascalu też można nieźle zaciemnić i nieładnie pisać kod [diabel] A te podwójne podkreślenia dolne to kwestia przyzwyczajenia, nie wygląda to aż tak źle ;)
Też tak można w Pascalu ;)
marcinEc dobrze mówi - kto tak wywołuje funkcje:
rzutowanie<float,int>(fA);
to nie html...
a po co o tym pisać po raz kolejny...? Hmm, chyba tylko początkujący piszą artykuły, nie mając za sobą doświadczeń i całej tej (trudnej i nieraz całkiem szerokiej) wiedzy...
Ale może kiedyś... :)
marcinEc: to napisz o tym.. kiedy przyzwyczaicie sie do tego ze 4p uwolniło dokumenty...
A co z dedukcją parametrów? przecież nie muszę pisać:
foo<float>(zmf1,zmf2);
Jest jeszcze specjalizacja szablonu.
OT:
A dlaczego tak napisałeś. Czyżby Pascal był złym językiem? Narazie widzę więcej przeciw niż za:
Jest też trochę zalet, ale...
Jak możesz to napisz jakie są zalety z Twojego punktu widzenia (kogoś kto - tak myślę - orientuje się już dosyć dobrze).
hallelujah! another soul saved!
Powoli (choć nie wiem czemu, bo widzę więcej wad niż zalet) przerzucam się z Pascala na C++. Słyszałem o szablonach funkcji ale nie wiedziałem jak się ich używa, teraz już wiem. Dzięki.
OT: To tak jak w Pascalu funkcje z operatorem overload.