Friday, 23 August 2013

Tricky Stuff

Keyword typename:

template <typename T> class MyClass {
typename T::SubType * ptr;
...
};


Now keyword typename is very important in the declaration above and is required otherwise compiler will treat T::SubType * ptr as multiplication of static member SubType inside T with ptr; T being generic type , it is programmer's job to tell compiler that SubType is a type inside T. 
so with typename the declaration means ptr is a pointer of SuyType.


Template template parameters

template t<typename T, typename Container>
class Stack {...}; //declaration

Stack<int, std::vector<int> > vStack; //stack of int using vector as container.

can this be written as

Stack<int, std::vector> > vStack; 

To do this template declaration changes as follows. Following applies to class templates only.

template <typename T, template< typename ELEM> class CONT = std::deque>
class Stack { ... };

Now in the code above second template parameter is a class template

template < typename ELEM > class CONT //and is defaulted to std::deque.

which effectively declare container as std::deque<ELEM> but what we want is std::deque<T>

so ELEM is not used hence we can ignore the type and modify the declaration as follows, that way same type T is used for std::deque.

template < typename T, template <typename> class CONT = std::deque>
class Stack{ ... };

//member functions change accordingly

template <typename T, template< typename> class CONT>
Stack<T,CONT>::push(const T& elem)
{
       elems.push_back(elem); 
}


'typename' or 'class'

one would argue that above declaration can be written something like

template <typename T, template<typename> typename CONT = std::deque>
class Stack {...}; //ERROR

//previous declaration:

template <typename T, template<typename> class CONT = std::deque>
class Stack {...}; //CORRECT


we replaced the word class with typename with class and that is an error because, this word class indicates that it is a class template or second template param of Stack is a class template. i.e. std::deque or any container for that matter is a class template hence the key word class is used as in a C++ class.

Initialising member types of type T ( generic type)

To make sure that a member of a class template, for which the type is parameterized, gets initialized, you have to define a default constructor that uses an initializer list to initialize the member:
template <typename T> class MyClass {
private: T x;
public:
MyClass() : x() {
// ensures that x is initialized even for built-in types }
...

}; 

Using string literals in as template params


// note: reference parameters

template <typename T>
inline T const& max (T const& a, T const& b) {

return a < b ? b : a; }
int main() 
{
  std::string s;
  ::max("apple","peach");    //OK same type
  ::max("apple","tomato");
// ERROR: different types ::max("apple",s); 

                                         // ERROR:       different types


here type of "apple" is char const[6] and that of tomato is char const[7] hence they are different type. solution is to call them using 
::max(std::string("apple"), std::string("tomato")); // now types are same.
or alternatively max can be defined without using references as follows

// note: nonreference parameters
template <typename T> inline T max (T a, T b)
{

        return a < b ? b : a; 
}
int main() 
{
     std::string s;
     ::max("apple","peach"); // OK: same type 
     ::max("apple","tomato"); // OK: to same type 
     ::max("apple",s); // ERROR: different types
}

For more information refer the book.

















No comments:

Post a Comment