270 likes | 416 Views
Templates and Functors. Joe Meehean. Pair Class Example. Suppose we wanted a class to store a pair of ints Access the first using first() and the second using second () Lets call it LCPair. class LCPair { public: LCPair ( int a ,int b) { this->first = a;
E N D
Templates and Functors Joe Meehean
Pair Class Example Suppose we wanted a class to store a pair of ints Access the first using first() and the second using second() Lets call it LCPair
class LCPair{ public: LCPair(inta,int b) { this->first = a; this->second = b; } int& first() { return this->first_; } int& second() { return this->second_; } private: int first_; int second_; };
Type Independent Classes • The type of the pair items doesn’t matter • we don’t do anything with them • Suppose we wanted to make LC Pair type independent • How do we do it? • Do we have to write a different pair class for every data type?
Type Independent Classes C++ Templates • The type of the pair items doesn’t matter • we don’t do anything with them • Suppose we wanted to make LC Pair type independent • How do we do it? • Do we have to write a different pair class for every data type?
template <typename Obj1, typename Obj2> class LCPair{ public: LCPair(constObj1& o1,const Obj2& o2) { this->first_ = o1; this->second_ = o2; } Obj1& first() { return this->first_; } Obj2& second() { return this->second_; } private: Obj1 first_; Obj2 second_; };
Class Templates • Need to declare what the generic/template types are • template <typenameYouChooseName> • generic type must follow the typename keyword • e.g., template <typename Obj1> • can define multiple generic types using a list • template <typenameO1,typename O2> • Then use the declared generic type like any other type
Class Templates • When initializing a templated class • must declare what types you want it to use • refer to class using ClassName<type-list> • e.g., LCPair<int,int> intPair; • Then use it like any other class
Class Templates int main(){ LCPair<int,int> intPair; LCPair<bool,bool> boolPair; LCPair<int,float> mixedPair; mixedPair.first() = 7; mixedPair.second() = 4.5; inti = mixedPair.first(); float f = mixedPair.second(); } Using a template class
Class Templates • A class template is not a class • it is a pattern for what will become a class • when you declare a class template variable • e.g., LCPair<int,int> intPair; • the compiler makes a whole new class file • replaces all instances of template types with declared types • e.g., Obj replaced with int • does this for each different declaration • LCPair<int,int> & LCPair<bool,bool> are classes
Type Independent Algorithms • What if we want to find the largest element in an array? • If the element overrides the > operator,the data type of the elements is irrelevant • Use Function Templates to solve this problem • uses similar syntax to class templates
Function Templates /** * Comparable must provide > operator */ template <typename Comparable> Comparable& findMax(Comparable* a, int size){ intmaxIndex = 0; for(size_ti = 1; i < size; i++){ if( a[i] > a[maxIndex] ){ maxIndex = i; } } return a[maxIndex]; }
Templates and Compilers • Compiler replaces all template types with actual types • If you use methods, constructors or operators on a template type • e.g., a[i] > a[maxIndex] • produces compile error if not defined on concrete types
Templates and Compilers • When using template types • always specify required methods & constructors in comments • e.g., /* Comparable must provide > operator */ • assume the template type is a class • e.g., Obj1 obj= 0; // NO, may not compile • e.g., Obj1 obj; // YES
Templates and Compilers • We always declare our classes in a .h file • And define their methods in a .cpp file • Many compilers cannot do this with templates • including Visual Studio and g++ • Template classes must be completely defined in the .h file
Recall: Function Templates /** * Comparable must provide > operator */ template <typename Comparable> Comparable& findMax(Comparable* a, int size){ intmaxIndex = 0; for(size_ti = 1; i < size; i++){ if( a[i] > a[maxIndex] ){ maxIndex = i; } } return a[maxIndex]; }
Comparing Objects • What if we want findMax to work for more complex objects • e.g., Student object • has Name, GPA, GradDate • what should > compare them on? • what if we want to be able to find max Name and max GPA all with one function?
Comparing Objects Functors • What if we want findMax to work for more complex objects • e.g., Student object • has Name, GPA, GradDate • what should > compare them on? • what if we want to be able to find max Name and max GPA all with one function?
Functors • Objects that act like functions • may have no data • require only one public method • Can make lots of different functors for same class • Using templates we can compare any element using any functor
// compare students by name class StudentNameCmp{ public: boolisGreaterThan( const Student& lhs, const Student& rhs){ return lhs.getName() > rhs.getName(); } }; // compare students by gpa class StudentGPACmp{ public: boolisGreaterThan( const Student& lhs, const Student& rhs){ return lhs.getGPA() > rhs.getGPA(); } };
/** * Comparator must provide * isGreaterThan(Object, Object) */ template < typename Object, typename Comparator> Object& findMax( Object* a, int size, Comparator cmp){ intmaxIndex = 0; for(size_ti = 1; i < size; i++){ if( cmp.isGreaterThan(a[i],a[maxIndex]) ){ maxIndex = i; } } return a[maxIndex]; }
Functors int main(){ Student students[15]; // fill in array ... // find the largest name Student maxName = findMax(students, 15, StudentNameCmp() ); // find the student with best GPA Student bestGPA = findMax(students, 15, StudentGPACmp() ); }
Functors • Making functors look like functions • Instead of defining isGreaterThan method • Override the operator() • known as the function call operator • calling it looks just like calling a non-member function
// compare students by name class StudentNameCmp{ public: booloperator()( const Student& lhs, const Student& rhs){ return lhs.getName() > rhs.getName(); } }; // compare students by gpa class StudentGPACmp{ public: booloperator()( const Student& lhs, const Student& rhs){ return lhs.getGPA() > rhs.getGPA(); } };
/** * Comparator must provide * function operator */ template <typename Object, typename Comparator> Object& findMax( Object* a, int size, Comparator cmp){ intmaxIndex = 0; for(size_ti = 1; i < size; i++){ if( cmp.isGreaterThan(a[i],a[maxIndex]) ){ if( cmp(a[i],a[maxIndex]) ){ maxIndex = i; } } return a[maxIndex]; }