MFC Programmer's SourceBook : Thinking in C++
Bruce Eckel's Thinking in C++, 2nd Ed Contents | Prev | Next

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* Data, Link* Next) {
      data = Data;
      next = Next;
    }
  } * _head;
  int owns;
public:
  TStack(int own = 1) : _head(0), owns(own) {}
  ~TStack();
  void push(T* Data) {
    _head = new Link(Data,_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;
  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);
      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! ";
    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

Contents | Prev | Next


Go to CodeGuru.com
Contact: webmaster@codeguru.com
© Copyright 1997-1999 CodeGuru