Monday, 5 August 2013

Class Templates


Class templates

  • Class Templates are same as function templates, but they are classes.
template <typaname T>
class Stack {

public:
        void push(const T& ref);
        T pop();
        T top(); 
        bool empty() {return elems.empty();} //inline
private:
        std::vector<T> elems;

};

T Stack<T>::pop() {
       if( elmems.empty())
       {
             throw std::out_of_range("pop: stack is empty");
       }
       T elem = elems.back(); //get the last element of vector
       elems.pop_back();        //remove the last element
       
       return elem;
}

  • code above is template delcaration for any type T
  • The member functions are declared, some of them defined inline.
  • Other are defined outside as 'function templates'
  • When templates is instantiated like Stack<int> intStack; then only class instance is created.
  • Instances of function are created only when the functions are called such as intStack.push(7); This way only push will be instantiated and not pop()
  • Thus C++ gives no overhead, you pay for what you use.
  • That way we can instantiate class templates for the types that do not support all the template member functions.
  • Any type is allowed in while instantiating templates as long as operations are supported.
  • Stack<Stack(int)> > intStackStack; // space> > is not required since C++11

Full specialization:

template <>
class Stack<std::string> {

public:
        void push(const std::string& ref);
        T pop();
        T top(); 
        bool empty() {return elems.empty();} //inline
private:
        std::vector<std::string> elems;

};
void Stack<std::string>
push(const std::string& ref) {
       elems.push_back(ref);
}
  • To specialize the class template use template<> syntax.
  • If class template is specialized then ALL the member function must be specialized by writing corresponding ordinary functions as shown above (push) for that type.
  • If that is not desirable then instead of specializing the class template individual member function can be specialized without specializing the class  itself.
  • Specialization can differ from the original implementation of template function or class template. ( that is why this called so! )
  • This specialization is called as full specialisation, i.e. all the types are known.

Partial specialization:

template <typename T1, typename T2>
class Part {...}  //original def.

template <typename T>
class Part<T,T> {...}

template <typename T1, typename T2>
class Part <T1*, T2*> {...}

template <typename T1, int>
class Part < T1,int> {...}
  • This is partial specialization at least one of the type is generic.
//use
Part<int, float> p1; //matches Part<T1,T2>
Part<float, int> p2; //matches Part<T1, int>
Part<float,float> p3; //matches Part<T,T>
Part<float*, float*> p4; //Error ambiguous matches Part<T1*,T2*> & Part<T1,T2> 
  • Partial specialization is allowed only for class templates.
  • Function templates must be fully specialized and cannot be partially specialized.

Default template arguments:

template <typename T, typename CONT = std::vector<T> >
class Stack {
public:
        void push(const T&);
        T pop();
        T top();
        bool empty() {return elems.empty();}
private:
        CONT elems; //generic container defaulted to std::vector.
};

template<typename T, typename CONT>
void Stack<T,CONT>::push(const T& ref) {
       elems.push_back(ref);
}
  • Thus, here default template argument is specified and that way if second argument is ignored then std::vector is used as container or you can change the container as per requirements. e.g.
//use
//stack of int implemented using default std::vector
Stack<int> intStack; 


Stack<double, std::deque<double> > dblStack;
//stack of doubles with std::deque<> as a container.






No comments:

Post a Comment