Class templates
- Class Templates are same as function templates, but they are classes.
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;
};
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.
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.
//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