c++ templates - university of california, davisgraphics.cs.ucdavis.edu/~joy/ecs40/lectures/c++...

24
C++ Templates David Camp

Upload: phungmien

Post on 03-Aug-2018

217 views

Category:

Documents


0 download

TRANSCRIPT

C++ Templates

David Camp

C Marcos

#define <identifier>(<parameter list>) <replacement token list>

#define min(i, j) (((i) < (j)) ? (i) : (j))

#define max(i, j) (((i) > (j)) ? (i) : (j))

#define RADTODEG(x) (x * 57.29578)

// What is the problem with using this macro

RADTODEG(a + b) // = (a + b * 57.29578)

C Marcos

#define PRETTY_PRINT(msg) \printf ("Message: '%s'\n", msg);

if (n < 10)PRETTY_PRINT("n is less than 10");

elsePRETTY_PRINT("n is at least 10");

error: expected expression before ‘else’—gcc 4.1.1

Why do we get this error message?

C Macro Problems

There are many problems with C macros: • There is no way for the compiler to verify that the

macro parameters are of compatible types. The macro is expanded without any special type checking.

• Debugging problems. May only show the macro or may step in but the variables are wrong

• Cause wrong code to be generated.

• See more about C Macros at http://en.wikipedia.org/wiki/C_macro

Function Templates

template<class T> const T& max( const T& i, const T& j ) {

return ((i < j) ? i : j) ;}

// use in codecout << max( 3, 7 ); // outputs 7

// Compiler create the following functionconst int& max( const int& x, const int& y ) {

return((i < j) ? i : j);}

Function Templates

int main(){

// calls max<int> (by argument deduction)std::cout << max( 3, 7 ) << std::endl;

// calls max<double> (by argument deduction)std::cout << max( 3.0, 7.0 ) << std::endl;

// The type is ambiguous, explicitly instantiate max<double>std::cout << max<double>( 3, 7.0 ) << std::endl;

return 0;}

Function Templates

• Perform identical operations for each type of data compactly and conveniently

• Based on the argument types provided in calls to the function, the compiler automatically instantiates separate object code functions to handle each type of call appropriately.

• STL algorithms are implemented as function templates

Class Templates• Class templates

– Allow type-specific versions of generic classes

• Format:template <class T>

class ClassName

{

// Class Definition

}

– Need not use "T", any identifier will work

– To create an object of the class, type

ClassName< type > myObject;

Example: Stack< double > doubleStack;

Class Templates Functions

• Template class functions– Declared normally, but preceded by template<class T>

• Generic data in class listed as type T

– Template class function definition for class Constructor:

template<class T>

ClassName< T >::ClassName( int size )

{

// Creates an array of type T

myArray = new T[size];

}

#define DEFAULT_STACK_SIZE 10

template < class T >class Stack{public:

Stack( int size = DEFAULT_STACK_SIZE ); // default constructor~Stack() { delete [] stackPtr; } // destructorbool push( const T& pushValue ); // push an element onto the stackbool pop( T& popValue ); // pop an element off the stack

private:int _size; // # of elements in the stackint _top; // location of the top elementT * _stackPtr; // pointer to the stack

bool isEmpty() const { return( top == -1 ); } // utilitybool isFull() const { return( top == size -1 ); } // functions

};

template < class T >Stack< T >::Stack( int size ){

_size = size > 0 ? size : DEFAULT_STACK_SIZE; _top = -1; // Stack is initially empty_stackPtr = new T[_ size ]; // allocate space for elements

}

// Push an element T onto the stack

// return true if successful, false otherwise

template< class T >

bool Stack< T >::push( const T &pushValue )

{

if( !isFull() )

{

stackPtr[ ++top ] = pushValue; // place item in Stack

return( true ); // push successful

}

return( false );// push unsuccessful

}

// Pop an element off the stack

template< class T >

bool Stack< T >::pop( T &popValue )

{

if( !isEmpty() )

{

popValue = stackPtr[ top-- ]; // remove item from Stack

return( true ); // pop successful

}

return( false ); // pop unsuccessful

}

int main(){

Stack< double > doubleStack( 5 );

cout << "Pushing elements onto doubleStack" << endl;for(double f = 1.1; doubleStack.push( f ) ; f += 1.1 ) { // if success true is returned

cout << f << ' ';}cout << "\nStack is full. Cannot push " << f << "\n\nPopping elements from doubleStack\n";while( doubleStack.pop( f ) ) // if success true is returned

cout << f << ' ';cout << "\nStack is empty. Cannot pop\n";

Stack< int > intStack;

cout << "\nPushing elements onto intStack\n";for(int i = 1; intStack.push( i ) ; ++i) { // if success true is returned

cout << i << ' ';}cout << "\nStack is full. Cannot push " << i << "\n\nPopping elements from intStack\n";while( intStack.pop( i ) ) // if success true is returned

cout << i << ' ';cout << "\nStack is empty. Cannot pop\n";return( 0 );

}

Stack Sample Output

Pushing elements onto doubleStack1.1 2.2 3.3 4.4 5.5Stack is full. Cannot push 6.6

Popping elements from doubleStack5.5 4.4 3.3 2.2 1.1Stack is empty. Cannot pop

Pushing elements onto intStack1 2 3 4 5 6 7 8 9 10Stack is full. Cannot push 11

Popping elements from intStack10 9 8 7 6 5 4 3 2 1Stack is empty. Cannot pop

Class Templates and Non-type Parameters

• Can use non-type parameters in templates– Default argument

– Treated as const

• Example:template< class T, int elements >

Stack< double, 100 > mostRecentSalesFigures;

• Declares object of type Stack< double, 100>

– This may appear in the class definition:

T stackHolder[ elements ]; //array to hold stack

• Creates array at compile time, rather than dynamic allocation at execution time

Templates and Inheritance• A class template can be derived from a template

class

• A class template can be derived from a non-template class

• A template class can be derived from a classtemplate

• A non-template class can be derived from a classtemplate

Templates and friends• Friendships allowed between a class template and

– Global function

– Member function of another class

– Entire class

• friend functions – Inside definition of class template X:

– friend void f1();

• f1() a friend function of all template classes

– friend void f2( X< T > & );

• f2( X< int > & ) is a friend function of X< int > only. The same applies for float, double, etc.

– friend void A::f3();

• Member function f3 of class A is a friend of all template classes

Templates and friends

– friend void C< T >::f4( X< T > & );

• C<float>::f4( X< float > & ) is a friend function of class X< float > only

• friend classes– friend class Y;

• Every member function of class Y is a friend with every template class made from X

– friend class Z< T >;

• Class Z< float > a friend of class X< float >, etc.

Template Parameters

C++ templates allow one to implement a generic Stack<T> template that has a type parameter T. T can be replaced with actual types.

Templates can have any number of parameters.

C++ allows you to specify a default template parameter, so the definition could now look like:

template Stack <class T = float, int elements = 100>

Template Specialization

• Template class specialization

overrides the template-generated code by providing special definitions for specific types

• Template class partial specialization

generate a specialization of the class for just one parameter

Template Specialization

template<>

const string& max<string>( const string& s1, const string& s2 )

{

if( s1.size() > s2.size() )

return( s1 );

return( s2 );

}

Partial Template Specialization

template< class L, class R >L add( L left, R right ){

return( left + right );}

template< class R >string add( string left, R right ){ostringstream s;s << left << right;return( s.str() );

}

Template Metaprogramming

template < int N > struct Factorial {const int value = N * Factorial<N - 1>::value;

};

template <>struct Factorial< 0 > {const int value = 1;

};

template <>struct Factorial< 1 > {const int value = 1;

};

Benefits of Templates

• C++ promotes code reusability. Templates provide a way to re-use source code

• Templates are type-safe. Because the types that templates act upon are known at compile time, the compiler can perform type checking before errors occur

• Create a type-safe collection class (for example, a stack) that can operate on data of any type

• Templates avoid some of the common errors found in code that use macros like function

Drawbacks to Templates

• Compiler support

• Poor error messages

• Code bloat

• Hard to find errors in Templates

• Hard to read error messages during compiling