Thursday, November 14, 2013

template template class

I posted it initially at
http://www.cplusplus.com/forum/general/116769/

#include <iostream>
using namespace std;

/*
 *   -------------------------------------
 *    1. template parameter  ( ordinary case )
 *   -------------------------------------
 *   template <class C>
 *   class takeAny
 *
 *   It means:
 *   takeAny only takes ordinary type, including template class,
 *   in as its template parameter, less restrictive
 *
 *   -------------------------------------
 *   -------------------------------------
 *    2. template template parameter  ( special case I'm talking about today. )
 *   -------------------------------------
 *   template <template <class T> class C>
 *   class takeTC_Only
 *
 *   It means:
 *   takeTC_Only ONLY takes "template class"
 *   in as its template parameter, more restrictive
 *
 *   -------------------------------------
 *
 *   We should consider "template <class T> class C" as a whole.
 *   "T"'s sole purpose is to indicate that "C" is a template class, which
 *  takeTC_Only expects when doing initialization.
 *
 *   In another word, we can use "C" as a type inside class takeTC_Only to declare variables.
 *   However when I do so inside class takeTC_Only, I also need to make sure that C is used as template
 *   class that must be initialized with other specific types, which is a tricky part.
 *
 *   Type "T" could NOT be used inside class takeTC_Only to declare variables.
 *   Again, its sole purpose is to indicate that "C" is a "template class" and class takeTC_Only
 *   must take a "template class" as its template class.
 *   In another word, if we feed class takeTC_Only with an ordinary class, then it will be an error
 *   because class takeTC_Only only expects a template class to get itself initialized.
 *
 */


template <class T>
class aTemplateClass
{
public:
        aTemplateClass(T b){a=b;}
        void print() const      {cout << "data is " << a <<endl;}
        T& get(){return a;}
private:
        T a;
};

class anOrdinaryClass
{
public:
        anOrdinaryClass(int b){a=b;}
        void print() const      {cout << "data is " << a <<endl;}
        int& get(){return a;}
private:
       int a;
};

// You can only feed in "a template class" as its template argument when
// initialize takeTC_Only.
template <template <class T> class C>
class takeTC_Only
{
public:
        takeTC_Only(C<int> b):a(b) { }
        void print() const { a.print();}
private:
     // Here is the tricky part: you need use "C" as template class.
        // You can NOT do "C<T>& a;" because it doesn't recognize "T" as template parameter.
        C<int>& a;
};

// You can either feed in "an ordianry class"  OR "a template class" as
// its template argument when initialize takeAny.
template <class C>
class takeAny
{
public:
        takeAny(C b):a(b) { }
        void print() const { a.print();}
private:
        C& a;
};


int main() {
        // ##############################################################
        // #  1. template class as template parameter : so-called template template class 
        // ###############################################################
        // takeTC_Only MUST take "a Template class" in as its template parameter.
        // "aTemplateClass" is a template class so it can be used to initialize takeTC_Only.
        aTemplateClass<int> a(3);

       // tricky part#2: you don't do "takeTC_Only<aTemplateClass<int> > takeTC(a); ", 
       // instead, you do  "takeTC_Only<aTemplateClass> takeTC(a);"
        takeTC_Only<aTemplateClass> takeTC(a);
        takeTC.print();

        // #######################################
        // #  2. any type as template parameter  
        // #######################################
        // template class takeAny takes either an Ordinary class OR a template class in as its template parameter.
        // 1. Take an ordinary class as template parameter.
        anOrdinaryClass b(3);
        takeAny<anOrdinaryClass> take_any(b);
        take_any.print();

        // 2. Take a template class as template parameter.
        takeAny<aTemplateClass<int> > take_any2(a);
        take_any2.print();

        return 0;
}
 
 
Three things a template class can take as template parameter: 
1) Type: that are preceded by the class or typename keywords , which represent types. 
    eg:   class T

2) Non-Type : regular typed parameters, similar to those found in functions.
    eg:    int N

3) Template :  that are preceded by the template keywords , which represent templates.   
    eg:    template <class U> class V
                     
template <class T, int N, template <class U> class V>
class Got_All_Three 
{
};


For example,
Got_All_Three<anOrdinaryClass, 100, aTemplateClass> gat;

or

Got_All_Three<aTemplateClass<int>, 100, aTemplateClass> gat; 


No comments:

Post a Comment