This is a note I made after revisiting templatetemplateclass. Hope it helps others out there too.
Here goes the code:
#include <iostream>
usingnamespace 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;
}
your terminology is a bit off, so it's difficult to follow.
There are three kinds of template parameters: non-type, type, and template. Your takeAny is a template with one type template parameter: it requires a type (not a value, not a template) to be instantiated. Your takeTC_Only is a template with one template template parameter, it requires a template (not a value, not a type) to be instantiated.
Thanks for a good summary.
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
{
};