C++ Templates
Parametric Polymorphism
void printData(int value){
cout << "The value is “ << value << endl;
}
void printData(double value){
cout << "The value is “ << value << endl;
}
void printData(string value){
cout << "The value is “ << value << endl;
}
template<typename T>
void printData(T value){
cout << "The value is “ << value
<< endl;
}
double d=4.75;
string s("hello");
bool b=false;
printData(3); //T is int printData(d); //T is double printData(s); //T is string printData(b); // T is bool
Function Template
template <typename T>
T GetMax (T a, T b) {
T result = (a>b)? a : b;
return result;
}
void main(){
int i=5, j=6, k;
double d=3.14, e=5.0, f;
k=GetMax<int>(i,j);
f=GetMax<double>(d,e);
f=GetMax<double>(i,e);
}
Definition
Usage
Specifying Actual Template Arguments
• Explicit:
• Implicit:
template<typename T>
void func(){}
int main(){
func<int>();
func<double>();
}
template<typename T>
void func(T value) {}
template<typename T,typename U>
T func2(U value) { return T(value);
}
int main(){
// T=int
func(3);
// T=int, U=double
func2<int>(3.5);
}
The compiler can only deduce template arguments of function templates
Class Template
template <typename T>
class MyQueue {
std::vector<T> data;
public:
void add(T const &d);
void remove();
void print();
};
void main(){
MyQueue<int> q;
q.add(1);
q.print();
q.remove();
q.print();
template <typename T>
void MyQueue<T>::add(T const &d){
data.push_back(d);
}
Declaration
Definition
Usage
Template Parameters
• Type parameters
• typename X or class X
• X can be used anywhere a type can be used
• Non-Type parameters
– compile-time constants
• int, bool, address of a global variable
• No floating point values or string literals
• Template parameters
– Next slide…
template<int i>
class A{};
A<3> a3;
A<sizeof(string)> as;
Template as a Template Parameter
• Enable a template to be parameterized by the name of another template.
• Example: a class that lets you choose a container type
– A container is also a template
template<template<typename T> class ContainerType>
class MyClass{
ContainerType<int> intContainer;
ContainerType<string> stringContainer;
};
MyClass<vector>;
MyClass<list>;
Default Template Parameters
• Just like functions
– If a parameter has a default specified, all subsequent parameters must also have a default specified.
– When referencing a template, parameters with default values can be omitted
– if a template parameter is omitted, all subsequent template parameters must also be omitted.
template<typename T1,typename T2=int,int i=23>
class MyClass{};
MyClass<double, string,46> mc1; // specify all parameters MyClass<string,double> mc2; // omit "i"
MyClass<string,double,23> mc3; // same as above MyClass<int> mc4; // all default
MyClass<int,int,0> mc5; // must specify "T2" to specify "i"
Templates Instantiation
• Two template instantiations refer to the same template if their parameters are all the same
typedef string MyString;
typedef vector<string> T1;
typedef vector<MyString> T2;
T1 vec1;
T2 vec2;
vector<string> vec3;
Instantiation of Member Functions
• Member functions of class templates are only instantiated if they are referenced.
template <typename T>
class MyClass{
public:
T* makeCopy(T* p){
return p->clone();
}
}; MyClass<int> mci; // OK double d;
MyClass<double> mcd; // OK
double* pd=mcd.makeCopy(&d); // error
Templates and Static Members
• Each instantiation of the template will have its own private copy of the static members.
template <typename T>
class X {
public: static T s ; } ;
template <typename T> T X<T>::s = 0 ;
Initialization value Member name
member type
It’s a template
Templates and Friends
template <typename T>
class X {
friend class Y<T>; // Y<T> is friend of X<T> only if they have // the same type parameter
friend class Foo; //class Foo is friend to all instances of X.
template <typename OtherType>
friend class Z<OtherType>;
// All instantiations of Z are friends to all // instantiations of X.
}
Templates and Inheritance
Templates and inheritance can be related in different ways
– A class template derived from a class template
instantiation template<typename T> class Base{…};template<typename T> class Derived : public Base<T>{…};
– A class template derived from a non-template class (hoisting)
class Base{…};template<typename T> class Derived : public Base{…};
– A non-template class derived from a class template
instantiation template<typename T> class Base{…};class Derived : public Base<ConcreteType>{…};
– Mixins
template<typename T> class Derived : public T {…};
Mixins
– A mixin is a class designed to provide functionality for another class.
14
template <typename T>
class LoggingClass : public T { public:
void execute(){
cout << “LOG: starting task “ << endl;
T::execute();
cout << “LOG: finishing task “ << endl;
} } ;
LoggingClass<MyClass1>() m1;
MyClass2 m2 = new LoggingClass<MyClass2>();
m1.execute();
static_cast<LoggingClass<MyClass2>>(m2).execute();
As long as a class supports an “execute” method, LoggingClass
can be used to add logging capabilities to the execution.
Mixins cont.
– Mixins can be used to add any mixture of functionalities to a class:
template <typename T>
class Flying: public T { public:
void fly(){ //do something } } ;template <typename T>
class Swimming: public T { public:
void swim(){ //do something } } ; template <typename T>
class Walking: public T { public:
void walk(){ //do something } } ;
class Animal{
…
… };
Swimming<Animal> fish;
Swimming<Walking<Animal>> penguin;
Swimming<Walking<Flying<Animal>>> duck;
Template Constraints
• Constraints on parameters are implicitly imposed
– operations that must work on objects of the appropriate type – class members that must exist
template<typename T>
void func(T& value) {
const T ref = value;
T* p = new T();
*p = ref;
T temp(23);
p->clone();
}
Constrains on T:
1. Cannot be a reference.
2. Must have a copy constructor.
3. Must have a destructor.
4. Must have a default constructor.
5. Must have an assignment Operator.
6. Must have a constructor T(int).
7. Must have member clone().
Template Specialization
• Allows defining different code for a specific set of template parameters
• Explicit specialization
template<typename T>
struct Printer {
void print(T t) {
cout << "the value is " << t << endl; } };
template<>
struct Printer<int> { void print(int n) {
cout << "the number is " << n << endl; } };
Compile-time Computations with Explicit Specialization
void foo(){
int x = Factorial<4>::value; // == 24 int y = Factorial<0>::value; // == 1 }
template<int N>
struct Factorial {
enum {value = N*Factorial<N-1>::value; } };
template <>
struct Factorial<0> { enum {value = 1; } };
Partial Specialization
Specializing for a subset of the template parameters
template <typename T,typename U>
struct SameType {
static const bool result = false;
};
template <typename T>
struct SameType<T,T> {
static const bool result = true;
};
void foo(){
cout<<"Is int the same type as double?" <<
(SameType<int,double>::result?"Yes":"No")<<endl;
cout<<"Is string the same type as string?" <<
(SameType<string,string>::result?"Yes":"No") <<endl;
}
Meta Operations
template <bool g, typename T, typename E>
struct IF {
typedef T RET;
};
template <typename T, typename E>
struct IF<false, T, E> { typedef E RET;
};
// if sizeof(int) < sizeof(long) then use long else use int IF<sizeof(int)<sizeof(long), long, int>::RET i;
typename keyword
• Used for denoting qualified, dependent types.
• Is T::something a type or a value?
template <typename T>
struct SameType { int x;
void foo() { T::something * x; } };
template <typename T>
struct SameType { int x;
void foo() { typename T::something * x; } };
A value
A Type
What Are Type Traits
Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details".
- Bjarne Stroustrup
What Are Type Traits?
• Compile-time code that exposes different charactaristics of types
• Can also be used to change types, or the program control flow
• Many Type Traits implementations added in C++
11.
• Under the <type_traits> header
• Type traits are often implemented using template
specialization, but not always.
Type Traits Examples
24
• Traits for checking type categories:
//generic definition:
template <typename T>
struct is_void{
static const bool value = false;
};
//void specialization:
template <>
struct is_void<void>{
static const bool value = true;
};
//generic definition:
template <typename T>
struct is_pointer{
static const bool value = false;
};
//pointer specialization:
template <typename T>
struct is_pointer <T*>{
static const bool value = true;
};
• Other available categories: is_enum, is_integral,
is_floating_point, is_function, is_abstract …
Type Traits Examples (cont.)
• Traits can also be used to check for supported operations:
• is_default_constructable, is_assignable, is_destructible
• To retrieve type relationships or qualities:
• is_base_of, is_same, alignment_of
• Or to change types:
• remove_pointer, make_unsigned
Type Traits Usage
• Example of changing control flow:
struct A{};
template <typename T>
struct someStruct{
void foo(){ //different implementation if A is base of T if (std::is_base_of<A,T>::value)
//do something else
//do something else }};