You are on page 1of 39

Computer Methods 3

ENEL3CCH1
Week Five
Recap of Week 4
Explicit and Implicit specialisation
Member function templates
Class templates
Discipline of Electrical, Electronic & Computer Engineering Bashan Naidoo
What we cover in week 5

• We look at template instantiation


• Implicit specialisation
• Explicit specialisation

• We look at simple templated OOP coding...


• Template member functions in normal classes
• Template classes with normal member functions
• Template classes with template member functions
• The Inclusion Model for templated class code organisation

• We deploy code samples at each step


Aside: Pointers and references
Let us now consider another variable of type “pointer to int”…
this is x
We can now dereference the pointer: *xptr = 20;
The dereferencing operator * takes an initialised pointer and returns the object it is pointing to
name: xptr address: &xptr type: int* value: &x size: 4 bytes of memory

Somewhere in memory Somewhere else in


memory

&xptr > xptr = &x; &x >

&x xptr 20 x
Aside: Pointers and references
Let us consider references…

Now we use the reference: int &xref = x;


xref = 40;
Somewhere in
memory

&x >

40 x xref
Function overloading and templates
• This template
#include <iostream> replaces all the
#include <string> overloaded
definitions of
NTswap().
/******************Function templates******************
* Since the structure and logic are identical in all *
* above functions, we can replace them with a single * • This must precede
* function template... below * main()
******************************************************/
• It can even process
template <typename T> strings
void NTswap(T &Num1, T &Num2) {
T temp = Num1;
Num1 = Num2; Note: These are
Num2 = temp; ordinary functions (not
} methods), and this is a
POP example (not OOP)
Function overloading and templates
From the compiler’s perspective…
• A template is not a normal function or class.
• It cannot be directly compiled. Why?

A single template represents a whole set of functions


Each function is a specialisation of the template

Generic single
template template

instantiation instantiation instantiation

Specific
Function template template template
(specialisaions) specialisation specialisation specialisation
Function overloading and templates
Instantiation of
specialisations From the compiler’s perspective…

Template • Templates must be converted to specialisations


(not • Then specialisations may be compiled
compileable)
• The conversion process is called instantiation
• Instantiation may follow two routes
• Implicit specialisation (where possible)
instantiation • Explicit specialisation (always possible)

Specialisation
(compileable
C++ code)
Function overloading and templates
Implicit instantiation of Implicit Specialisation Example #include <iostream>
specialisations typename using namespace std;

template <class T> template <class T>


Template T GetMax (T a, T b) { T GetMax (T a, T b) {
return (a>b?a:b); return (a>b?a:b);
} }

k =GetMax(i,j); n =GetMax(l,m); int main () {


instantiation int i=5, j=6, k;
long l=10, m=5, n;
k =GetMax(i,j);
n=GetMax(l,m);
int GetMax (int a, int b) { long GetMax (long a, long b) {
cout << k << endl;
return (a>b?a:b); return (a>b?a:b);
cout << n << endl;
} }
return 0;
Specialisation }
Compileable C++ code
Function overloading and templates
Explicit instantiation of Explicit Specialisation Example #include <iostream>
specialisations using namespace std;

template <class T> template <class T>


Template T GetMax (T a, T b) { T GetMax (T a, T b) {
return (a>b?a:b); return (a>b?a:b);
} }

int main () {
instantiation int i=5, j=6, k;
k =GetMax<int>(i,j); n =GetMax<long>(l,m); long l=10, m=5, n;
k =GetMax< int >(i,j);
n=GetMax< long >(l,m);
int GetMax (int a, int b) { long GetMax (long a, long b) {
cout << k << endl;
return (a>b?a:b); return (a>b?a:b);
cout << n << endl;
} }
return 0;
Specialisation }
Compileable C++ code
Function overloading and templates
Explicit instantiation of Explicit Specialisation Example
specialisations (multiple template parameters) //code frag from main()

Template template <class T, class U> int i,j;


T GetMin (T a, U b) { long l;
return (a<b?a:b); i = GetMin<int,long> (j,l);
}

instantiation OOPS!
i = GetMin<int,long> (j,l); Exercise for you!
The function returns an
int. Can it return b as
int GetMin (int a, long b) { an int? Will this
return (a<b?a:b); compile? You test this
} and fix it if needed.
Specialisation
Compileable C++ code
Introduction to templates in OOP
So we have already looked at…
• Function overloading
• Function templates
• Instantiation of implicit and explicit template specialisations

These were presented as simple POP concepts where a main program calls
an overloaded function or a template, that is defined outside of main().

Remember… function templates are just special cases of function


overloading.

We now look at the basics of templates in the OOP paradigm


Introduction to templates in OOP
We now look at the basics of templates in the OOP paradigm…

More specifically, we will look at:

• Member function templates and

• Class templates

This gets complex very quickly, so we only do the basics.


Remember that this module is not about C++. It just uses C++
Member function templates
A class definition can contain member function templates

Assume that we have defined a class with public member functions…


We can insert a public function template into that class
This member function template will be specialised when the class is
instantiated.
…and NOT when the
function is called.
Examples follow…
Member function templates
Lets start with a simple OOP example (no templates yet)

#include <iostream> Output:

class MFTdemo1 { OBJ1.ModMyVar(3) = 9


public:
int ModMyVar(int var) {
return 3 * var;
} No surprises here. Output is
}; as expected…

int main()
{
MFTdemo1 OBJ1;
std::cout << "OBJ1.ModMyVar(3) = " << OBJ1.ModMyVar(3) << "\n";
}
Major limitation: Can only
use integer values!!!
Member function templates
Now we convert member function into a member template and test it
#include <iostream> This is a normal class Output:
with a public
class MFTdemo2 { template member OBJ2.ModMyVar(3) = 9
public: function OBJ2.ModMyVar(3.6) = 10.8
template<typename T>
T ModMyVar(T var) {
return 3 * var; Implicit specialisation of
} the member function
}; template has produced the
desired output…
int main()
{
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3) = " << OBJ2.ModMyVar(3) << "\n";
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
} Problem Sorted!
Member function templates
Now we convert member function into a member template and test it
#include <iostream>
Complexity is shifted Output:
into the class
class MFTdemo2 {
Remember… OBJ2.ModMyVar(3) = 9
public:
• ******Abstraction****** OBJ2.ModMyVar(3.6) = 10.8
template<typename T>
• Write once, use many
T ModMyVar(T var) {
return 3 * var;
} Simple, happy calling program
}; Totally blind to the hidden complexity
Remember:
int main() • One class definition, many instances!
{ • Write once (complex), use many (simple)
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3) = " << OBJ2.ModMyVar(3) << "\n";
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Member function templates
An alternate syntax for the template member function
#include <iostream>
This is a normal class Output:
class MFTdemo2 {
with a public template
public: OBJ2.ModMyVar(3.6) = 10.8
member declaration
template<typename T>
T ModMyVar(T var);
};
The template member function is just like a
template<typename T> free template function but…
T MFTdemo2::ModMyVar(T var) { it is declared inside the containing class, and
return 3 * var; its external definition is scoped to its
} containing class.

int main(){
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Member function templates
Now we combine and test template and non-template member overloads
class MFTdemo3 {
public: This is a normal class Output:
int ModMyVar(int var) { with template and non-
return 5 * var; template overloads of OBJ3.ModMyVar(3) = 15
} ModMyVar() OBJ3.ModMyVar(3.6) = 10.8
template<typename T>
T ModMyVar(T var) {
return 3 * var; Executes the non-template Executes the template
} member function if it member function. A non-
}; exists; which is the case. template overload does not
(output = 5 * 3) exist (output = 3 * 3.6)
int main() {
MFTdemo3 OBJ3;
std::cout << "OBJ3.ModMyVar(3) = " << OBJ3.ModMyVar(3) << "\n";
std::cout << "OBJ3.ModMyVar(3.6) = " << OBJ3.ModMyVar(3.6) << "\n";
}
Class templates
Class templates are similar to function templates

• Can be done if we have class overloads with the same logic


and structure, but with different datatypes.

• Class templates allow us to create a generic class definition,


which in turn may be instantiated to various specialisations.

• Each specialisation will have the same logic and structure, but
will have unique datatypes (like the overloads it replaces).
Class templates
First we look at a normal class…
Output:
#include <iostream>
My height is 183 cm.
class Measurement {
private:
int value;
public:
int getValue() { return value; }
void setValue(int val) { value = val; }
};

int main() {
Measurement heightCM;
heightCM.setValue(183);
std::cout << "My height is " << heightCM.getValue() << " cm.\n";
}
Class templates
Convert it to a class template…
Output:
#include <iostream>
template<typename T> My height is 183 cm.
class Measurement {
private:
T value;
public: We are forced to use
T getValue() { return value; } EXPLICIT specialisation.
void setValue(T val) { value = val; } Can you explain why?
};

int main() {
Measurement<int> heightCM;
heightCM.setValue(183);
std::cout << "My height is " << heightCM.getValue() << " cm.\n";
}
Class templates
template<typename T>
class Measurement {
private:
T value;
public:
T getValue() { return value; }
void setValue(T val) { value = val; }
};

Measurement<int> heightCM; Measurement<double> heightM;

class Measurement <int> { class Measurement <double> {


private: private:
int value; double value;
public: public:
int getValue() { return value; } double getValue() { return value; }
void setValue(int val) { value = val; } void setValue(double val) { value = val; }
}; };
class type is: Measurement<int> class type is: Measurement<double>
Instantiation of
specialisations

Class templates Template


(not
compileable)

Try a different datatype…


Output:
#include <iostream> instantiation
template<typename T> My height is 1.83 m.
class Measurement {
private: Why explicit specialisation?
T value; Specialisation happens at object instantiation
public: (same as template function specialisation), but
T getValue() { return value;
the }object instantiations do not include any Specialisation
void setValue(T val) { value = val;
data. }
So compiler cannot determine class (compileable
}; datatype at instantiation, therefore we must C++ code)
stipulate the datatype.
int main() {
Measurement<double> heightM;
heightM.setValue(1.83);
std::cout << "My height is " << heightM.getValue() << " m.\n";
}
Class templates
What if we want to define a method outside the template class?
#include <iostream>
template<typename T> Define the method Why copy this across?
First declare outside but copy
class Measurement {
the method the class template
private: Because this is an
inside the declaration across
T value; overloaded template
containing class
public: class and there are
T getValue() { return value; } multiple versions of
void setValue(T val) { value = val; } the class.
Define the T RangeMin(T tollerance);
method outside }; So the external
but scope the
method definition
method into its
template<typename T> must be scoped back
containing class
T Measurement<T>::RangeMin(T tollerance) { into the correct
return value - value * tollerance / 100; version of the class
}
Class templates
Example: Eskom supplies 230Vac with 5% tolerance (sometimes!)
So we can use the class to compute the minimum allowable voltage
Exercise: Create a RangeMax method to find the max allowable voltage

int main() {
Measurement<int> VoltV;
VoltV.setValue(230);
std::cout << "Eskom voltage should be " << VoltV.getValue() << " V (nominal).\n";
std::cout << "Eskom voltage should be at least " << VoltV.RangeMin(5) << " V.\n";
}

Output:

Eskom voltage should be 230 V (nominal).


Eskom voltage should be at least 219 V.
Template classes with template
member functions
We have seen template member functions inside of normal
classes

We have seen template classes

Can we have template member functions inside a template


class?

Yes…
Template classes with template
member functions
#include <iostream>
template<typename T>
class Measurement {
private: We have a template class
T value; …with…
public: a template member declaration
T getValue() { return value; }
void setValue(T val) { value = val; }
template<typename toll>
Here we have the
toll RangeMin(toll tollerance);
template member definition
};
that is scoped to the
containing template class
template <typename T> Measurement<T>
template <typename toll>
toll Measurement<T>::RangeMin(toll tollerance) {
return value - value * tollerance / 100;
}
Template classes with template
member functions
#include <iostream>
template<typename T>
class Measurement {
WARNING! This is not a class…
private:
It is a template that represents
T value;
several class overloads!!!
public:
T getValue() { return value; }
There are many versions of this
void setValue(T val) { value = val; }
class…
template<typename toll>
toll RangeMin(toll tollerance);
}; So… the compiler must scope
this function into the correct
class version… so we fully
template <typename T> specify the class instance like
template <typename toll> this… Measurement<T>
toll Measurement<T>::RangeMin(toll tollerance) {
return value - value * tollerance / 100;
}
Template classes with template
member functions
#include <iostream>
template<typename T>
class Measurement {
private:
T value;
public:
T getValue() { return value; }
1. class tempate void setValue(T val) { value = val; }
template<typename toll> 3. class name (full)
toll RangeMin(toll tollerance);
};
2. method tempate

template <typename T>


template <typename toll>
toll Measurement<T>::RangeMin(toll tollerance) {
return value - value * tollerance / 100;
}
Template classes with template
member functions
Output… can you explain what happened here?

int main() {
Measurement<int> VoltV;
VoltV.setValue(230);
std::cout << "Eskom voltage should be " << VoltV.getValue() << " V (nominal).\n";
std::cout << "Eskom voltage should be at least " << VoltV.RangeMin(5.0) << " V.\n";
}

Output:

Eskom voltage should be 230 V (nominal).


Eskom voltage should be at least 218.5 V.
Exercise:
1. Add a RangMax template method
2. Deploy Measurement<double> class specialisation
Aside: Towards “Inclusion Model” of organising
template class code
These code fragments can be organised into separate files…
#include <iostream>
This looks like a class
class MFTdemo2 { header
public:
template<typename T> So… Let us try to
T ModMyVar(T var); separate these into
}; three files like we did
This looks like a class in previous lectures
implementation file with non-template
template<typename T>
T MFTdemo2::ModMyVar(T var) { examples
return 3 * var;
}
This looks like a your
main application file
int main(){
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Aside: Towards “Inclusion Model” of organising
template class code
#pragma once #include “MFTdemo.h”

class MFTdemo2 { template<typename T>


public: T MFTdemo2::ModMyVar(T var) {
template<typename T> return 3 * var;
T ModMyVar(T var); }
};
Its an OOP oops!!!
Looks fine, compiles fine, but
fails to link and execute…
WHY???
#include <iostream>
#include “MFTdemo.h”

int main(){
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Aside: Towards “Inclusion Model” of organising
template class code
#pragma once #include “MFTdemo.h”

class MFTdemo2 { template<typename T>


public: T MFTdemo2::ModMyVar(T var) {
EachT> cpp file compiles return
template<typename independently
3 * var; and
T ModMyVar(T var); }
apparently successfully… but linking seems to
};
fail. Why?
1>MFTdemo.obj : error LNK2019: unresolved external symbol
"public: double __thiscall MFTdemo::ModMyVar<double>(double)"
#include <iostream>
(??$ModMyVar@N@MFTdemo@@QAENN@Z) referenced in function _main
#include “MFTdemo.h”

int main(){
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Aside: Towards “Inclusion Model” of organising
template class code
Each cpponce
#pragma file compiles independently and apparently
#include “MFTdemo.h” successfully…
but linking seems to fail. Why?
class MFTdemo2 { template<typename T>
public: T MFTdemo2::ModMyVar(T var) {
In order to instantiate
template<typename T> the template return
(early3 * binding),
var; the compiler
T ModMyVar(T
needs var);
two things… }
};
• The template definition (we placed it in MFTdemo.cpp)
• The call to the template function (we placed it in MyProg.cpp)

But these<iostream>
#include are in two files that compile separately. So when
#include “MFTdemo.h”
compiling MyProg.cpp, the template definition is missing, and when
compiling
int main(){MFTdemo.cpp the call is missing. The binding is not
clear and the
MFTdemo2 OBJ2;compiler creates a reference for the linker to
std::cout
resolve. << "OBJ2.ModMyVar(3.6)
Unfortunately = " << OBJ2.ModMyVar(3.6)
the linker << "\n"; it.
may fail to resolve
}
Aside: Towards “Inclusion Model” of organising
#pragma once template class code
class MFTdemo2 {
public: #include “MFTdemo.h”
template<typename T>
T ModMyVar(T var); template<typename T>
}; T MFTdemo2::ModMyVar(T var) {
return 3 * var;
template<typename T> }
T MFTdemo2::ModMyVar(T var) {
return 3 * var;
Solution one: Insert all the class code in the class
}
header file and remove the class .cpp file. This
effectively produces one file again before
compilation. So early binding is successful.
#include <iostream>
#include “MFTdemo.h” Unfortunately, we no longer have separate
declaration and definition files for our class.
int main(){ Solution works but it is not comfortable.
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Aside: Towards “Inclusion Model” of organising
template class code
#pragma once #include “MFTdemo.h”

class MFTdemo2 { template<typename T>


public: T MFTdemo2::ModMyVar(T var) {
template<typename T> return 3 * var;
T ModMyVar(T var); }
};

#include <iostream> Solution two: Include the class declaration and


#include “MFTdemo.h” definition files in MyProg.cpp. This solution also
#include “MFTdemo.cpp” produces one file again. So it like solution one, it
compiles and links
int main(){
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Aside: Towards “Inclusion Model” of organising
template class code
#pragma once #include “MFTdemo.h”

class MFTdemo2 { template<typename T>


public: T MFTdemo2::ModMyVar(T var) {
template<typename T> return 3 * var;
T ModMyVar(T var); }
};

#include <iostream> Solution two: Easy fix, works well, but we are
#include “MFTdemo.h” now including .cpp files. This breaks traditional
#include “MFTdemo.cpp” practice where only .h files are included. This
leads us to solution three…
int main(){
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Aside: Towards “Inclusion Model” of organising
template class code
#pragma once #pragma once
#include “MFTdemo.h”
class MFTdemo2 {
public: template<typename T>
template<typename T> T MFTdemo2::ModMyVar(T var) {
T ModMyVar(T var); return 3 * var;
}; }

#include <iostream> Solution Three: Place the class definitions and


#include “MFTdemo.h” declarations in two header files. Then include
#include “MFTdemoDefs.h” both. Easy fix, works well, we are now including
two .h files. There is no .cpp file for the class…
int main(){ similar to solution one, but the class has two files.
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}
Aside: Final “Inclusion Model” of organising
template class code
#pragma once #pragma once
#include “MFTdemo.h”
class MFTdemo2 {
public: template<typename T>
template<typename T> T MFTdemo2::ModMyVar(T var) {
T ModMyVar(T var); return 3 * var;
}; }

#include <iostream>
#include “MFTdemo.h” Solution Three: best solution for
#include “MFTdemoDefs.h” templated classes!!!

int main(){
MFTdemo2 OBJ2;
std::cout << "OBJ2.ModMyVar(3.6) = " << OBJ2.ModMyVar(3.6) << "\n";
}

You might also like