cpp
// The return value of the template function
// asz() is a compile-time constant
#include "../arraySize.h"
#include <iostream>
using namespace std;
int main() {
int a[12], b[20];
const int sz1 = asz(a);
const int sz2 = asz(b);
int c[sz1], d[sz2];
} ///:~
Of course, just making a variable of a built-in type a const does not guarantee it’s actually a compile-time constant, but if it’s used to define the size of an array (as it is in the last line of main( )), then it must be a compile-time constant.
Chapter 15: Multiple Inheritance
621
Template specializations
Partial specialization
Pointer specialization
Partial ordering of function templates
Member templates
//: C19:Applist2.cpp
// Apply a function to a TStack
#include <iostream>
using namespace std;
template<class T> class TStack {
struct Link {
T* data;
Link* next;
Link(T* dat, Link* nxt) {
data = dat;
next = nxt;
}
}* _head;
int _owns;
public:
TStack(int own = 1) : _head(0), _owns(own) {}
~TStack();
void push(T* dat) {
_head = new Link(dat, _head);
}
T* peek() const { return _head->data; }
T* pop();
int owns() const { return _owns; }
void owns(int newownership) {
_owns = newownership;
}
class Iterator;
friend class Iterator;
Chapter 15: Multiple Inheritance
622
class Iterator {
TStack<T>::Link* p;
public:
Iterator(const TStack<T>& ts)
: p(ts._head) {}
Iterator(const Iterator& ts)
: p(ts.p) {}
// operator++ returns boolean indicating end:
int operator++() {
if(p->next)
p = p->next;
else p = 0; // Indicates end of list
return int(p);
}
int operator++(int) { return operator++(); }
// Smart pointer:
T* operator->() const {
if(!p) return 0;
return p->data;
}
T* current() const {
if(!p) return 0;
return p->data;
}
// int conversion for conditional test:
operator int() const { return p ? 1 : 0; }
};
Iterator head() { return Iterator(*this); }
// 0 arguments, any type of return value:
template<class R>
void applist(R(T::*f)()) {
Iterator it = head();
while(it) {
(it.current()->*f)();
it++;
}
}
// 1 argument, any type of return value:
template<class R, class A>
void applist(R(T::*f)(A), A a) {
Iterator it = head();
while(it) {
(it.current()->*f)(a);
Chapter 15: Multiple Inheritance
623
it++;
}
}
// 2 arguments, any type of return value:
template<class R, class A1, class A2>
void applist(R(T::*f)(A1, A2),
A1 a1, A2 a2) {
Iterator it = head();
while(it) {
(it.current()->*f)(a1, a2);
it++;
}
}
// Etc., to handle maximum probable arguments
};
template<class T> T* TStack<T>::pop() {
if(_head == 0) return 0;
T* result = _head->data;
Link* oldHead = _head;
_head = _head->next;
delete oldHead;
return result;
}
template<class T> TStack<T>::~TStack() {
Link* cursor = _head;
while(_head) {
cursor = cursor->next;
// Conditional cleanup of data:
if(_owns) delete _head->data;
delete _head;
_head = cursor;
}
}
class Gromit { // The techno-dog
int arf;
public:
Gromit(int arf = 1) : arf(arf + 1) {}
void speak(int) {
for(int i = 0; i < arf; i++)
cout << "arf! ";
Chapter 15: Multiple Inheritance
624
cout << endl;
}
char eat(float) {
cout << "chomp!" << endl;
return 'z';
}
int sleep(char, double) {
cout << "zzz..." << endl;
return 0;
}
void sit(void) {}
};
int main() {
TStack<Gromit> dogs;
for(int i = 0; i < 5; i++)
dogs.push(new Gromit(i));
dogs.applist(&Gromit::speak, 1);
dogs.applist(&Gromit::eat, 2.0f);
dogs.applist(&Gromit::sleep, 'z', 3.0);
dogs.applist(&Gromit::sit);
} ///:~
Why virtual member template functions
are disallowed
Nested template classes
Template-templates
//: C19:TemplateTemplate.cpp
#include <vector>
#include <iostream>
#include <string>
using namespace std;
// As long as things are simple, this approach
// works fine:
Chapter 15: Multiple Inheritance
625
template<typename C>
void print1(C& c) {
typename C::iterator it;
for(it = c.begin(); it != c.end(); it++)
cout << *it << " ";
cout << endl;
}
// Template-template argument must be a class;
// cannot use typename:
|