
Understanding Function Templates in C++
Explore the concept of function templates in C++, which simplify function overloading and enable polymorphism by allowing the data type to be a parameter. Learn how to make functions work for multiple variable types using function overloading and type parameters in template functions.
Download Presentation

Please find below an Image/Link to download the presentation.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.
You are allowed to download the files provided on this website for personal or commercial use, subject to the condition that they are used lawfully. All files are the property of their respective owners.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.
E N D
Presentation Transcript
Introduction A general definition of functions and classes Further simplifies the previous function overloading Another form of polymorphism In a template, the data type is the parameter! The precise definitions of the template functions and classes are determined in run-time based on the data type!
Function Templates Consider the following function int max (int x, int y) { return (x > y? x : y); } It only works for the int type of variables! How can we make it work for other types of variables?
Function Templates Use function overloading! float max (float x, float y) { return (x > y? x : y); } double max (double x, double y) { return (x > y? x : y); } char max (char x, char y) { return (x > y? x : y); }
Function Templates Use function overloading! float max (float x, float y) { return (x > y? x : y); } double max (double x, double y) { return (x > y? x : y); } char max (char x, char y) { return (x > y? x : y); }
Function Templates! template <class T> T max (T x, T y) { return (x > y? x : y); } Type parameter First line called "template prefix" Tells compiler what s coming is "template" And that T is a type parameter
Function Templates! template <class T> T max (T x, T y) { return (x > y? x : y); } First line called "template prefix" Tells compiler what s coming is "template" And that T is a type parameter In template <class T>, "class" means "type", or "classification ! It is NOT the class we learned before!
Function Templates! template <class T> T max (T x, T y) { return (x > y? x : y); } First line called "template prefix" Tells compiler what s coming is "template" And that T is a type parameter In template <class T>, "class" means "type", or "classification ! It is NOT the class we learned before! To avoid confusion, one can use typename .
Function Templates! template <class T> T max (T x, T y) { return (x > y? x : y); } T can be replaced by any type in the run time Predefined or user-defined (like a C++ class type) In function definition body: T used like any other type, just like it has been defined already Note: one can use other symbol than "T", but T is the "traditional" usage
How Does this Work? Consider the following example #include <iostream> using namespace std; template<typename T> T abs(T x) { return x < 0? -x : x; } int main() { int n = -5; double d = -5.5; cout << abs(n) << endl; cout << abs(d) << endl; return 0; } Output is 5 5.5
How Does this Work? Consider the following example #include <iostream> using namespace std; If not using template, at least two abs functions need to be defined: One for int type, the other for double type template<typename T> T abs(T x) { return x < 0? -x : x; } int main() { int n = -5; double d = -5.5; cout << abs(n) << endl; cout << abs(d) << endl; return 0; } Output is 5 5.5
How Does this Work? Consider the following example #include <iostream> using namespace std; In run-time, compiler determines the actual type for T based on the type of the input variable template<typename T> T abs(T x) { return x < 0? -x : x; } int main() { int n = -5; double d = -5.5; cout << abs(n) << endl; cout << abs(d) << endl; return 0; }
How Does this Work? Consider the following example #include <iostream> using namespace std; In run-time, compiler determines the actual type for T based on the type of the input variable template<typename T> T abs(T x) { return x < 0? -x : x; } For instance, abs(n), n is int type int main() { int n = -5; double d = -5.5; cout << abs(n) << endl; cout << abs(d) << endl; return 0; }
How Does this Work? Consider the following example #include <iostream> using namespace std; In run-time, compiler determines the actual type for T based on the type of the input variable template<typename T> T abs(T x) { return x < 0? -x : x; } For instance, abs(n), n is int type The compiler then creates the following function based on the template int main() { int n = -5; double d = -5.5; cout << abs(n) << endl; cout << abs(d) << endl; return 0; } int abs(int x) { return x < 0? -x : x; }
Difference Between Template Functions and Normal Functions Compiler won t generate instance for template functions during compiling. It generates when it is called (see abs example). If a template function is used by several other places in different .cpp files, the template function and its body need to be put in the .h file not only the declaration. The function pointer can only point to instance of the template function.
Back to the max function We now can use template to address our issue with the max function! #include <iostream> using namespace std; template<class T> T max(T x, T y) { return x > y? x : y; } void main() { int n1 = -5, n2 = 0; double d1 = -5.5, d2 = -5.9; cout << max(n1, n2) << endl; cout << max(d1, d2) << endl; }
Swap values example #include <iostream> using namespace std; void main() { int n1 = -5, n2 = 0; double d1 = -5.5, d2 = -5.9; ABC obj1(3, 4.4),obj2(3.1, 0.2); swapVals(n1, n2); swapVals(d1, d2); swapVals(obj1, obj2); } template<class T> T swapVals(T &x, T &y) { T tmp = x; x = y; y = tmp; } class ABC{ public: ABC(float inx=0, float iny=0) {x=inx; y=iny;} private: float x, y; }; We can also use it to swap the values of two objects!!!
What is the problem of the following example? // declare template function template<class T> void showStuff(int stuff1, T stuff2, T stuff3); void main() { int n1 = -5, n2 = 0.5; double d1 = -5.5, d2 = -5.9; ABC obj1(3, 4.4),obj2(3.1, 0.2); showStuff(1, n1, n2); showStuff(2, d1, d2); showStuff(3, obj1, obj2); } // define the template function template<class T> void showStuff(int stuff1, T stuff2, T stuff3) { cout << stuff1 << endl << stuff2 << endl << stuff3 << endl; } class ABC{ public: ABC(float inx=0, float iny=0) {x=inx; y=iny;} private: float x, y; };
What is the problem of the following example? // declare template function template<class T> void showStuff(int stuff1, T stuff2, T stuff3); void main() { int n1 = -5, n2 = 0.5; double d1 = -5.5, d2 = -5.9; ABC obj1(3, 4.4),obj2(3.1, 0.2); showStuff(1, n1, n2); showStuff(2, d1, d2); showStuff(3, obj1, obj2); } // define the template function template<class T> void showStuff(int stuff1, T stuff2, T stuff3) { cout << stuff1 << endl << stuff2 << endl << stuff3 << endl; } cout<< cannot handle ABC type of objects! Solution? class ABC{ public: ABC(float inx=0, float iny=0) {x=inx; y=iny;} private: float x, y; };
What is the problem of the following example? // declare template function template<class T> void showStuff(int stuff1, T stuff2, T stuff3); void main() { int n1 = -5, n2 = 0.5; double d1 = -5.5, d2 = -5.9; ABC obj1(3, 4.4),obj2(3.1, 0.2); showStuff(1, n1, n2); showStuff(2, d1, d2); showStuff(3, obj1, obj2); } // define the template function template<class T> void showStuff(int stuff1, T stuff2, T stuff3) { cout << stuff1 << endl << stuff2 << endl << stuff3 << endl; } cout<< cannot handle ABC type of objects! Solution? class ABC{ public: ABC(float inx=0, float iny=0) {x=inx; y=iny;} friend ostream& operator<<(ostream& os, ABC& obj); private: float x, y; }; Define an overload operator function! ostream& operator<<(ostream& os, ABC& obj) { os<< x= <<x<< , y= <<y<<endl; return os; }
Multiple Type Parameters Can have: template<class T1, class T2> Not typical Usually only need one "replaceable" type Cannot have "unused" template parameters Each must be "used" in definition Error otherwise!
What is the problem of the following template functions? template<class T1, class T2> T1 max (T1 num1, T1 num1) { return num1 > num2 ? num1 : num2; } T2 min (T2 num1, T2 num2) { return num1 > num2 ? num2 : num1; }
What is the problem of the following template functions? template<class T1, class T2> T1 max (T1 num1, T1 num1) { return num1 > num2 ? num1 : num2; } T2 is not used! T2 min (T2 num1, T2 num2) { return num1 > num2 ? num2 : num1; }
What is the problem of the following template functions? template<class T1, class T2> T1 max (T1 num1, T1 num1) { return num1 > num2 ? num1 : num2; } T2 is not used! Missing a template prefix! T2 min (T2 num1, T2 num2) { return num1 > num2 ? num2 : num1; }
What is the output of the following program? #include <iostream> using namespace std; template<class T> T max(T x, T y) { return x > y? x : y; } void main() { int n1 = -5, n2 = 0; double d1 = -5.5, d2 = -5.9; cout << max(n1, d2) << endl; cout << max(d1, n2) << endl; }
What is the output of the following program? #include <iostream> using namespace std; template<class T> T max(T x, T y) { return x > y? x : y; } void main() { int n1 = -5, n2 = 0; double d1 = -5.5, d2 = -5.9; cout << max(n1, d2) << endl; cout << max(d1, n2) << endl; } Compiling error! T ambiguous How to fix it?
Class Templates We can also define template class, which can be considered as the generalized classes (i.e., can be used to generate actual classes in run-time). template<class T> class Pair { public: Pair(); Pair(T firstVal, T secondVal); void setFirst(T newVal); void setSecond(T newVal); T getFirst() const; T getSecond() const; private: T first; T second; };
Class Templates We can also define template class, which can be considered as the generalized classes (i.e., can be used to generate actual classes in run-time). template<class T> class Pair { public: Pair(); Pair(T firstVal, T secondVal); void setFirst(T newVal); void setSecond(T newVal); T getFirst() const; T getSecond() const; private: T first; T second; }; template prefix declaration of the template class
Class Templates We can also define template class, which can be considered as the generalized classes (i.e., can be used to generate actual classes in run-time). template<class T> Pair<T>::Pair(T firstVal, T secondVal) { first = firstVal; second = secondVal; } template prefix definition of the member functions of the template class template<class T> void Pair<T>::setFirst(T newVal) { first = newVal; } Need to repeat this prefix for each member function Class name before:: is Pair<T> !
Class Templates How to use the template class? create a class with T = int Pair<int> score; Pair<char> seats; class Pair { public: secondVal); private: }; Pair(); Pair(int firstVal, int create a class with T = char void setFirst(int newVal); void setSecond(int newVal); int getFirst() const; int getSecond() const; int first; int second;
Class Templates Use the template class as the parameter of a function int addUP(const Pair<int>& the_Pair); create a class with T = int class Pair { public: secondVal); private: }; Pair(); Pair(int firstVal, int void setFirst(int newVal); void setSecond(int newVal); int getFirst() const; int getSecond() const; Overall, template types can be used anywhere standard types can int first; int second;
Class Templates We can further define the following function as a template to avoid defining new overload. int addUP(const Pair<int>& the Pair); char addUP(const Pair<char>& the Pair); float addUP(const Pair<float>& the Pair); How?
Class Templates We can further define the following function as a template to avoid defining new overload. int addUP(const Pair<int>& the_Pair); char addUP(const Pair<char>& the_Pair); float addUP(const Pair<float>& the_Pair); template<class T> T addUp(const Pair<T> & the_pair) { return the_pair.first + the_pair.second; }
Class Templates We can further define the following function as a template to avoid defining new overload. int addUP(const Pair<int>& the_Pair); char addUP(const Pair<char>& the_Pair); float addUP(const Pair<float>& the_Pair); Template<class T> T addUp(const Pair<T> & the_pair) { return the_pair.first + the_pair.second; } Of course, the + operator should apply to the summation of T type of objects!
Another example class calc { public: int multiply(int x, int y); int add(int x, int y); }; template<class T> class calc { public: T multiply(T x, T y); T add(T x, T y); }; int calc::multiply(int x, int y) { return x*y; } template<class T> T calc::multiply(T x, T y) { return x*y; } int calc::add(int x, int y) { return x+y; } T calc::add(T x, T y) { return x+y; } What is the problem of this class template?
Another example class calc { public: int multiply(int x, int y); int add(int x, int y); }; template<class T> class calc { public: T multiply(T x, T y); T add(T x, T y); }; int calc::multiply(int x, int y) { return x*y; } template<class T> T calc::multiply(T x, T y) { return x*y; } should be calc<T> int calc::add(int x, int y) { return x+y; } T calc::add(T x, T y) { return x+y; } What is the problem of this class template?
Another example template<class T> class calc { public: T multiply(T x, T y); T add(T x, T y); }; class calc { public: int multiply(int x, int y); int add(int x, int y); }; int calc::multiply(int x, int y) { return x*y; } template<class T> T calc<T>::multiply(T x, T y) { return x*y; } int calc::add(int x, int y) { return x+y; } template<class T> T calc<T>::add(T x, T y) { return x+y; } What is the problem of this class template?
Restrictions on Type Parameter Only "reasonable" types can be substituted for T Consider: Assignment operator must be "well-behaved" Copy constructor must also work If T involves pointers, then destructor must be suitable! Similar issues as function templates
Type Definitions Can define new "class type name" To represent specialized class template name Example: typedef Pair<int> PairOfInt; Name "PairOfInt" now used to declare objects of type Pair<int>: PairOfInt pair1, pair2; Equivalent to: Pair<int> pair1, pair2; Name can also be used as parameter, or anywhere else type name allowed void fun (PairOfInt &obj);
Friends and Templates Friend functions can be used with template classes Same as with ordinary classes Simply requires type parameter where appropriate Very common to have friends of template classes Especially for operator overloads (as we ve seen)
Templates and Inheritance Nothing new here Derived template classes Can derive from template or non-template class Derived class is then naturally a template class Syntax same as ordinary class derived from ordinary class
template <class T> class Foo { public: Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg) { /* do something for foo */ } T Foo_T; // either a TypeA or a TypeB - TBD foo_arg_t _foo_arg; }; template <class T> class Bar : public Foo<T> { public: Bar (const foo_arg_t bar_arg, const a_arg_t a_arg) : Foo<T>(bar_arg) // base-class initializer { Foo<T>::Foo_T = T(a_arg); } Bar (const foo_arg_t bar_arg, const b_arg_t b_arg) : Foo<T>(bar_arg) { Foo<T>::Foo_T = T(b_arg); } void BarFunc (); };
Summary Function templates Define functions with parameter for a type Class templates Define class with parameter for subparts of class Predefined vector and basic_string classes are template classes Can define template class derived from a template base class
More Compiler Complications Check your compiler s specific requirements Some need to set special options Some require special order of arrangement of template definitions vs. other file items Most usable template program layout: Template definition in same file it s used Ensure template definition precedes all uses Can #include it