Class Templating
Class templates and template classes.
Non-type template parameters.
Friends.
Default types.
Member function templates.
Typeid on template classes.
Variadic templates.
Class templates and template classes.
Non-type template parameters.
Friends.
Default types.
Member function templates.
Typeid on template classes.
Variadic templates.
In the previous set of notes we introduced templates for functions. If we need to create several similar classes, it may be useful to consider developing a class template in which at least one type is generic or parameterized. The syntax for class templating is similar to that for function templating. So we write a class template that the compiler turns into template classes.
Classes are blueprints for objects, so class templates are blueprints for blueprints. Class templates are sometimes referred to as parameterized types, effectively incomplete types where there is a to-bespecified type.
template<typename T>
class Number {
private:
T theNumber;
public:
Number(const T&);
void display();
};
template<typename T>
Number<T> :: Number(const T& n)
{
theNumber = n;
}
template<typename T>
void Number<T> :: display()
{
cout << theNumber << endl;
}
...
int main()
{
Number<int> anInt(50);
Number<double> aDouble(1.234);
Number<char> aChar('A');
anInt.display();
aDouble.display();
aChar.display();
// anInt = aChar; //This won’t work
return 0;
}
template <int p, int i>
class is_prime {
public:
enum { prim = ( (p % i) && is_prime<p, i - 1>::prim ) };
};
template <int p>
class is_prime<p, 1> {
public:
enum { prim = 1 };
};
template <int i>
class Prime_print { // primary template for loop to print prime numbers
public:
Prime_print<i - 1> a;
enum { prim = is_prime<i, i - 1>::prim };
void f()
{
a.f();
if (prim) cout << "prime number:" << i << std::endl;
}
};
template<>
class Prime_print<1> { // full specialization to end the loop
public:
enum { prim = 0 };
void f() {}
};
#ifndef LAST
#define LAST 18
#endif
int main()
{
Prime_print<LAST> a;
a.f();
}
In class definitions, templated or not, member functions may have their own template parameters.
template<typename T>
class Storage {
// ...
public:
template <typename R>
void action(R first, R last);
//...
};
The typeid operator can be applied to template classes.
The type of an object that is an instance of a template class is in part determined by what data is used for its generic data when the object is instantiated.
Two instances of the same template class that are created using different data are therefore considered to be different types.
template <typename T>
class myclass {
T a;
public:
myclass(T i) {
a = i;
}
// ...
};
int main()
{
myclass<int> o1(10), o2(9);
myclass<double> o3(7.2);
cout << "Type of o1 is ";
cout << typeid(o1).name() << endl;
cout << "Type of o2 is ";
cout << typeid(o2).name() << endl;
cout << "Type of o3 is ";
cout << typeid(o3).name() << endl;
cout << endl;
if (typeid(o1) == typeid(o2))
cout << "o1 and o2 are of the same type\n";
if (typeid(o1) == typeid(o3))
cout << "Error\n";
else
cout << "o1 and o3 are different types\n";
return 0;
}
Yup, it’s another ellipsis (…) and this is also new to C++11.
template<typename … Args> void g(Args … args)
{
cout << sizeof…(Args) << endl;
cout << sizeof…(args) << endl;
}
The two lines output, respectively, the number of type parameters and the number of function parameters.