Extra material for the paper:

Stronger Statically Typed C++ Through Recurring Inheritance

submitted to the 2nd Workshop on C++ Template Programming (in conjunction with OOPSLA), Tampa Bay, Florida, USA, October 14, 2001.



Get a compressed archive of all files: tmpw01-src.tar.gz or tmpw01-src.zip

Nota bene: an appendix has been added that does not appear in the paper.




1  Introduction

Generic decorator pattern (file decorator.cc):

// this file goes with the paper:
// Alexandre Duret-Lutz, Thierry Geraud, and Akim Demaille.
// Generic Design Patterns in C++. In the Proceedings of the 6th
// USENIX Conference on Object-Oriented Technologies and Systems (COOTS),
// pages 189-202, San Antonio, Texas, USA, January-February 2001.


#include <iostream>
using std::cout;
using std::endl;



class ConcreteComponent {
public:
  void Operation() {
    cout << "ConcreteComponent::Operation" << endl;
  }
};



template<class C>
class ConcreteDecoratorA : public C
{
public:
  void Operation() {
    C::Operation();
    addedState = 1;
  }
protected:
  int addedState;
};



template<class C>
class ConcreteDecoratorB : public C
{
public:
  void Operation() {
    C::Operation();
    AddedBehaviour();
  }
protected:
  void AddedBehaviour() {
    cout << "ConcreteDecoratorB::AddedBehaviour" << endl;
  }
};



int main()
{
  ConcreteDecoratorB<ConcreteComponent> cb;
  cb.Operation();
}


Generic template method pattern (file templmeth.cc):

// this file goes with the paper:
// Alexandre Duret-Lutz, Thierry Geraud, and Akim Demaille.
// Generic Design Patterns in C++. In the Proceedings of the 6th
// USENIX Conference on Object-Oriented Technologies and Systems (COOTS),
// pages 189-202, San Antonio, Texas, USA, January-February 2001.


#include <iostream>
using std::cout;
using std::endl;



template<class I>
class SuperiorOf {
protected:
  SuperiorOf() {
  }
  I& Self() {
    return static_cast<I&>(*this);
  }
};



template<class I>
class AbstractClass : public SuperiorOf<I>
{
public:
  void TemplateMethod() {
    // ...
    PrimitiveOperation1();
    // ...
    PrimitiveOperation2();
    // ...
  }
  void PrimitiveOperation1() {
    Self().PrimitiveOperation1_impl();
  }
  void PrimitiveOperation2() {
    Self().PrimitiveOperation2_impl();
  }
};



class ConcreteClass : public AbstractClass<ConcreteClass>
{
public:
  void PrimitiveOperation1_impl() {
    cout << "ConcreteClass::PrimitiveOperation1" << endl;
  }
  void PrimitiveOperation2_impl() {
    cout << "ConcreteClass::PrimitiveOperation2" << endl;
  }
};



int main()
{
  ConcreteClass obj;
  obj.TemplateMethod();
}




2  Recurring Inheritance

2.2  Text-Book Case

``Vertical'' recurring hierarchy (file vertical.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"


//
//  ``Vertical'' recurring hierarchy:
//
//   A*
//   |
//   B*
//   |
//   C*
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
class A : public Void< A<I> > {
public:
  void echo() {
    cout << "A" << endl;
  }
};


template<class I = Bottom>
class B : public A< B<I> > {
public:
  void echo() {
    cout << "B" << endl;
  }
};


template<class I = Bottom>
class C : public B< C<I> > {
public:
  void echo() {
    cout << "C" << endl;
  }
};



//
//  strong statically typed foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(A<T>& a) {
  to_exact(a).echo();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  A<> a;  foo(a);
  B<> b;  foo(b);
  C<> c;  foo(c);
}


``Horizontal'' recurring hierarchy (file horizontal.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"


//
//  ``Horizontal'' recurring hierarchy:
//
//     A*
//    /  \
//  B1*   B2*
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
class A : public Void< A<I> > {
public:
  void echo() {
    cout << "A" << endl;
  }
};


template<class I = Bottom>
class B1 : public A< B1<I> > {
public:
  void echo() {
    cout << "B1" << endl;
  }
};


template<class I = Bottom>
class B2 : public A< B2<I> > {
public:
  void echo() {
    cout << "B2" << endl;
  }
};



//
//  strong statically typed foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(A<T>& a) {
  to_exact(a).echo();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  A<>  a;   foo(a);
  B1<> b1;  foo(b1);
  B2<> b2;  foo(b2);
}


2.3  Exact Type

The equipment for recurring hierarchies (file exact_type.hh):

#ifndef EXACT_TYPE_HH
#define EXACT_TYPE_HH



//
//  Top, Bottom, and Void
//
//////////////////////////////////////////////////////////////////////


class Top {
protected:
  Top() {}
};


class Bottom {
private:
  Bottom();
};


template<class I = Bottom>
class Void : public Top {
protected:
  Void() {}
};




//
//  inferior traits
//
//////////////////////////////////////////////////////////////////////


template<class>
struct inferior;

template<template<class> class C,
         class I>
struct inferior< C<I> > {
 typedef I type;
};

// special mixin:

template<template<template<class> class, class> class M,
         template<class> class S,
         class I>
struct inferior< M<S,I> > {
 typedef I type;
};




//
//  exact traits
//
//////////////////////////////////////////////////////////////////////


namespace misc {

  template<class T>
  struct find_exact;

  template<class T, class I>
  struct helper {
   typedef typename find_exact<I>::type type;
  };

  template<class T>
  struct helper<T, Bottom> {
   typedef T type;
  };

  template<class T>
  struct find_exact {
   typedef typename inferior<T>::type I;
   typedef typename helper<T,I>::type type;
  };
}

template<class T>
struct exact {
 typedef typename misc::find_exact<T>::type type;
};




//
//  exact proc
//
//////////////////////////////////////////////////////////////////////


template<class T>
typename exact<T>::type* to_exact(Void<T>* ptr) {
  return static_cast<typename exact<T>::type*>(ptr);
}

template<class T>
const typename exact<T>::type* to_exact(const Void<T>* ptr) {
  return static_cast<const typename exact<T>::type*>(ptr);
}

template<class T>
typename exact<T>::type& to_exact(Void<T>& ref) {
  return static_cast<typename exact<T>::type&>(ref);
}

template<class T>
const typename exact<T>::type& to_exact(const Void<T>& ref) {
  return static_cast<const typename exact<T>::type&>(ref);
}



//
//  solve_cast traits
//
//////////////////////////////////////////////////////////////////////


template<template<class> class C,
         class T>
C<T>& solve_cast(C<T>& obj) { return obj; }

template<template<class> class C,
         class T>
const C<T>& solve_cast(const C<T>& obj) { return obj; }

template<template<class, class> class C,
         class T1, class T2 >
C<T1,T2>& solve_cast(C<T1,T2>& obj) { return obj; }

template<template<class, class> class C,
         class T1, class T2 >
const C<T1,T2>& solve_cast(const C<T1,T2>& obj) { return obj; }

template<template<class, class, class> class C,
         class T1, class T2, class T3 >
C<T1,T2,T3>& solve_cast(C<T1,T2,T3>& obj) { return obj; }

template<template<class, class, class> class C,
         class T1, class T2, class T3 >
const C<T1,T2,T3>& solve_cast(const C<T1,T2,T3>& obj) { return obj; }



#endif




3  Resulting Properties

3.1  Generalization of the Curiously Recurring Template Pattern

Limitation of the CRTP (file crtp-pb.cc):

#include <iostream>
using std::cout;
using std::endl;


//
//  ``Deep'' hierarchy and the Curiously Recurring Template Pattern
//
//      A
//    /   \
//   B1    B2
//         |
//         B20
//
//////////////////////////////////////////////////////////////////////


template<class T>
struct A {
  T& self() {
    return static_cast<T&>(*this);
  }
  void m() {
    self().n();
    // ...
  }
};


struct B1 : public A<B1> {
  void n() { cout << "B1::n" << endl; }
};


struct B2 : public A<B2> {
  void n() { cout << "B2::n" << endl; }
};


struct B20 : public B2 {
  void n() { cout << "B20::n" << endl; }
};



//
//  foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(T& a) {
  a.m();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main()
{
  B1  b1;   foo(b1);   // B1::n
  B2  b2;   foo(b2);   // B2::n
  B20 b20;  foo(b20);  // B2::n!
}


Overcoming the limitation (file crtp-sol.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"

//
//  ``Deep'' recurring hierarchy and the CRTP
//
//      A*
//    /   \
//   B1*   B2*
//          |
//         B20*
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct A : public Void< A<I> > {
  void m() {
    to_exact(this)->n();
  }
};


template<class I = Bottom>
struct B1 : public A< B1<I> > {
  void n() { cout << "B1::n" << endl; }
};


template<class I = Bottom>
struct B2 : public A< B2<I> > {
  void n() { cout << "B2::n" << endl; }
};


template<class I = Bottom>
struct B20 : public B2< B20<I> > {
  void n() { cout << "B20::n" << endl; }
};



//
//  foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(T& a) {
  a.m();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  B1<>  b1;   foo(b1);   // B1::n
  B2<>  b2;   foo(b2);   // B2::n
  B20<> b20;  foo(b20);  // B20::n
}


3.2  Bounded Quantification and Parameterized Functions

With no bound (file bound-off.cc):

//
//  foo with no bounded quantification
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(T& a) {
  a.m();          // (*)
}



//
//  two structs: one conforms, the other does not
//
//////////////////////////////////////////////////////////////////////


struct B1 {
  void m() {
    // ...
  }
};


struct Z {
};



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  B1 b;  foo(b);  // ok
  Z  z;  foo(z);  // => error at line (*)
}


Bounding Formal Parameters of Functions (file bound-on.cc):

#include "static_isa.h" // from http://oonumerics.org/tmpw00/mcnamara.html
#include "exact_type.hh"


//
//  a bound map to a struct and foo with bounded quantification
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct A : public Void< A<I> > {
  // structural_check:
  MAKE_TRAITS;
  template<class Self> static void check_structural() {
    void (Self::*_m)() const = &Self::m;
    (void)_m;
  }
protected:
  ~A() {
    RequireBoth< I, A<I> >();
    // means:
    // I is required to be a sub-class of A<I>
    // *and* structural checking is performed
  }
};


template<class T>
void foo(A<T>& a) {
  to_exact(a).m();
}



//
//  two structs: one conforms, the other does not
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct B1 : public A< B1<I> > {
  void m() {
    // ...
  }
};


struct Z {
};



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  B1<> b;  foo(b);  // ok
  Z    z;  foo(z);  // error
}


Allowing Massive Overloading (file overload-sol.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"


//
//  bounds and concrete classes
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct D : public Void< D<I> > {
protected: D() {}
};


template<class I = Bottom>
struct D1 : public D< D1<I> > {
};


template<class I = Bottom>
struct E : public Void< E<I> > {
protected: E() {}
};


template<class I = Bottom>
struct E1 : public E< E1<I> > {
};


template<class I = Bottom>
struct F : public Void< F<I> > {
protected: F() {}
};


template<class I = Bottom>
struct F1 : public F< F1<I> > {
};



//
//  overloaded functions
//
//////////////////////////////////////////////////////////////////////


template<class T, class U>
void bar(D<T>& d, E<U>& e) {
  cout << "bar(D,E)" << endl;
}


template<class T, class U>
void bar(D<T>& d, F<U>& f) {
  cout << "bar(D,F)" << endl;
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  D1<> d;
  E1<> e;
  bar(d,e);
}


Overloading with metaprogramming (file overload-meta.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "static_isa.h"


//
//  interfaces and concrete classes
//
//////////////////////////////////////////////////////////////////////


struct D {
protected: D() {}
};


struct D1 : public D {
};


struct E {
protected: E() {}
};


struct E1 : public E {
};


struct F {
protected: F() {}
};


struct F1 : public F {
};



//
//  overloaded functions
//
//////////////////////////////////////////////////////////////////////


struct bar_DE {
  template<class D, class E>
  static void exec(D& d, E& e) {
    cout << "bar_DE::exec" << endl;
  }
};


struct bar_DF {
  template<class D, class F>
  void exec(D& d, F& f) {
    cout << "bar_DF" << endl;
  }
};


template<class D, class T>
void bar(D& d, T& t) {
  typedef typename IF< Named<T,E>::valid, bar_DE, bar_DF >::RET bar_t;
  bar_t::exec(d, t);
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  D1 d;
  E1 e;
  bar(d,e);
}


Disambiguating Diamond-Shaped Inheritance (file diamond.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"


//
//  ``Diamond-shaped'' recurring hierarchy:
//
//     A*
//    /  \
//   B1*  B2*
//    \  /  \
//     C1*   C2*
//       \  /
//        D*
//
//////////////////////////////////////////////////////////////////////



template<class I = Bottom>
class A : public Void< A<I> > {
public:
  void echo() {
    cout << "A" << endl;
  }
};


template<class I = Bottom>
class B1 : public A< B1<I> > {
public:
  void echo() {
    cout << "B1" << endl;
  }
};


template<class I = Bottom>
class B2 : public A< B2<I> > {
public:
  void echo() {
    cout << "B2" << endl;
  }
};


template<class I = Bottom>
class C1 :
  public B1< C1<I> >,
  public B2< C1<I> >
{
public:
  void echo() {
    cout << "C1" << endl;
  }
};


template<class I = Bottom>
class C2 : public B2< C2<I> > {
public:
  void echo() {
    cout << "C2" << endl;
  }
};


template<class I = Bottom>
class D :
  public C1< D<I> >,
  public C2< D<I> >
{
public:
  void echo() {
    cout << "D" << endl;
  }
};



//
//  strong statically typed foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(A<T>& a) {
  to_exact(a).echo();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  D<> d;
  foo(solve_cast<B1>(d));
  foo(solve_cast<C2>(d));
}


Handling Mixins (file mixin.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"



//
//  some classes
//
//////////////////////////////////////////////////////////////////////


template< class I = Bottom >
struct A : public Void< A<I> > {
};


template< class I = Bottom >
struct B1 : public A< B1<I> > {
  void m() const {
    cout << "B1::m" << endl;
  }
  void n() const {
    cout << "B1::n" << endl;
  }
};


template< class I = Bottom >
struct B2 : public A< B2<I> > {
  void m() const {
    cout << "B2::m" << endl;
  }
};



//
//  mixins
//
//////////////////////////////////////////////////////////////////////


template< template<class> class S, class I = Bottom >
struct Mixin : public S< Mixin<S,I> > {
  typedef S< Mixin<S,I> > Super;
  void m() const {
    cout << "Mixin::m" << endl;
    this->Super::m();
  }
};


template< template<class> class S, class I = Bottom >
struct SubMixin : public Mixin<S, SubMixin<S,I> > {
  typedef Mixin<S, SubMixin<S,I> > Super;
  void m() const {
    cout << "SubMixin::m" << endl;
    this->Super::m();
  }
};



//
//  foo
//
//////////////////////////////////////////////////////////////////////


template< class T >
void foo(A<T>& a) {
  to_exact(a).m();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main()
{
  Mixin<B1> b1;
  foo(b1);  // gives: Mixin::m
            //        B1::m

  SubMixin<B2> b2;
  foo(b2);  // gives: SubMixin::m
            //        Mixin::m
            //        B2::m
}


3.3  Solving the Point/ColorPoint Case

Bad code (file color-pb.cc):

#include <iostream>
using std::cout;
using std::endl;




//
//  Point
//
//////////////////////////////////////////////////////////////////////


struct Point
{
  typedef Point This;

  Point(int x, int y) :
    x(x),
    y(y) {
  }
  bool operator==(const This& rhs) const {
    return x == rhs.x && y == rhs.y;
  }
protected:
  int x, y;
};



//
//  ColorPoint
//
//////////////////////////////////////////////////////////////////////


struct ColorPoint : public Point
{
  typedef ColorPoint This;
  typedef Point Super;

  ColorPoint(int x, int y, int c) :
    Super(x, y),
    c(c) {
  }
  bool operator==(const This& rhs) const {
    return Super::operator==(rhs) && c == rhs.c;
  }
protected:
  int c;
};



//
//  foo
//
//////////////////////////////////////////////////////////////////////


void foo(const Point& p1, const Point& p2) {
  cout << (p1 == p2 ? "true" : "false")
       << endl;
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main()
{
  Point      a(0,5);
  ColorPoint b(0,5,1);
  foo(a, b);            // true!
}


Good code (file color-sol.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"



//
//  F_EQ
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct F_EQ
  : public Void< F_EQ<I> >
{
  typedef F_EQ<I> This;

  bool operator==(const This& rhs) const {
    return to_exact(this)->eq(to_exact(rhs));
  }
};



//
//  operator!=
//
//////////////////////////////////////////////////////////////////////


template<class T>
bool operator!=(const F_EQ<T>& lhs,
		const F_EQ<T>& rhs) {
  return ! lhs.operator==(rhs);
}



//
//  Point
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct Point
  : public F_EQ< Point<I> >
{
  typedef Point<I> This;

  Point(int x, int y) :
    x(x),
    y(y) {
  }
  bool eq(const This& rhs) const {
    return x == rhs.x && y == rhs.y;
  }
protected:
  int x, y;
};



//
//  ColorPoint
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct ColorPoint :
  public Point< ColorPoint<I> >
{
  typedef ColorPoint<I> This;
  typedef Point<This> Super;

  ColorPoint(int x, int y, int c) :
    Super(x, y),
    c(c) {
  }
  bool eq(const This& rhs) const {
    return Super::eq(rhs) && c == rhs.c;
  }
protected:
  int c;
};



//
//  foo
//
//////////////////////////////////////////////////////////////////////


template<class P>
void foo(const Point<P>& p1, const Point<P>& p2) {
  cout << (p1 == p2 ? "true" : "false")
       << endl;
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main()
{
  Point<>      a(0,5);
  ColorPoint<> b(0,5,1);
  ColorPoint<> c(0,5,1);

  foo(a, b);  // error at compile-time
  foo(b, c);  // true
}




4  Practical Point of View

4.1  Limitation

Contravariant methods (file contrav.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"



//
//  First hierarchy
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct Base : public Void< Base<I> > {
};


template<class I = Bottom>
struct Derived : public Base< Derived<I> > {
};



//
//  Second hierarchy with contravariant methods
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct A : public Void< A<I> > {
  template<class T>
  void m(Derived<T>& d) {
    to_exact(this)->m(d);
  }
};


template<class I = Bottom>
struct B1 : public A< B1<I> > {
  template<class T>
  void m(Base<T>& b) {
    cout << "A1::m" << endl;
  }
};




//
//  foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(A<T>& a) {
  Derived<> d;
  a.m(d);
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main()
{
  A1<> a1;
  foo(a1);
}


4.2  Enhancing Generic Libraries

STL-like programming (file stl-pb.cc):

#include <iostream>
using std::cout;
using std::endl;



//
//  hierarchy
//
//////////////////////////////////////////////////////////////////////


struct B2 {
  void m() { cout << "B2::m" << endl; }
};


struct B20 : public B2 {
  void m() { cout << "B20::m" << endl; }
};



//
//  foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(T& a) {
  // ...
  a.m();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  B20 b;
  foo(b);                    // B20::m
  foo(static_cast<B2&>(b));  // B2::m!
}


Better code (file stl-sol.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"



//
//  reccurring hierarchy
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
struct A : public Void< A<I> > {
protected:
  A() {}
};


template<class I = Bottom>
struct B2 : public A< B2<I> > {
  void m() { cout << "B2::m" << endl; }
};


template<class I = Bottom>
struct B20 : public B2< B20<I> > {
  void m() { cout << "B20::m" << endl; }
};



//
//  foo'n bar
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(A<T>& _a) {
  typedef typename exact< A<T> >::type A;
  A& a = to_exact(_a);
  // ...
  a.m();
}


template<class T>
void bar_with_upcast(B2<T>& b) {
  foo(b);
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main() {
  B20<> b;
  foo(b);              // B20::m
  bar_with_upcast(b);  // B20::m
}




Appendix

`inferior' is required to be specialized when classes have more than one parameter (file rec-pb.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type.hh"



//
//  inferior traits ---second part
//  this code is useless :(
//
//////////////////////////////////////////////////////////////////////


template<template<class, class> class C,
         class T,
         class I>
struct inferior< C<T,I> > {
 typedef I type;
};

template<template<class, class, class> class C,
         class T1, class T2,
         class I>
struct inferior< C<T1,T2,I> > {
 typedef I type;
};



//
//  recurring hierarchy
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
class A : public Void< A<I> > {
};


// we have to explicitely specialize `inferior':

template<class U, class I> struct B;

template<class U, class I>
struct inferior< B<U,I> > { typedef I type; };

// otherwise we get the following error:
//
// ambiguous class template instantiation for `struct inferior< B<int,Bottom> >'
// candidates are: struct inferior< C<T,I> >
//                 struct inferior< C<I> >


template<class U, class I = Bottom>
struct B : public A< B<U,I> > {
  void m() {
    cout << "B::m" << endl;
  }
};



//
//  foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(A<T>& a) {
  to_exact(a).m();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main()
{
  B<int> b;
  foo(b);
}


new version of our equipment with improved `inferior' traits (file exact_type_vrec.hh):

#ifndef EXACT_TYPE_HH
#define EXACT_TYPE_HH


//
//  Top, Bot, rec, Bottom, and Void
//
//////////////////////////////////////////////////////////////////////


struct Top {
protected:
  Top() {}
};


struct Bot {
private:
  Bot();
};

template<class>
struct rec {
};

typedef rec<Bot> Bottom;


template<class I = Bottom>
class Void : public Top {
protected:
  Void() {}
};




//
//  inferior traits
//
//////////////////////////////////////////////////////////////////////


template<class>
struct inferior;

template<class I>
struct inferior< rec<I> > {
  typedef I type;
};

template<template<class> class C,
         class I>
struct inferior< C< rec<I> > > {
 typedef I type;
};

template<template<class, class> class C,
         class T,
         class I >
struct inferior< C<T, rec<I> > > {
  typedef I type;
};

template<template<class, class, class> class C,
         class T1, class T2,
         class I >
struct inferior< C<T1, T2, rec<I> > > {
  typedef I type;
};




//
//  exact traits
//
//////////////////////////////////////////////////////////////////////


namespace misc {

  template<class T>
  struct find_exact;

  template<class T, class I>
  struct helper {
   typedef typename find_exact<I>::type type;
  };

  template<class T>
  struct helper<T, Bot> {
   typedef T type;
  };

  template<class T>
  struct find_exact {
   typedef typename inferior<T>::type I;
   typedef typename helper<T,I>::type type;
  };
}

template<class T>
struct exact {
 typedef typename misc::find_exact<T>::type type;
};




//
//  exact proc
//
//////////////////////////////////////////////////////////////////////


template<class T>
typename exact<T>::type* to_exact(Void<T>* ptr) {
  return static_cast<typename exact<T>::type*>(ptr);
}

template<class T>
const typename exact<T>::type* to_exact(const Void<T>* ptr) {
  return static_cast<const typename exact<T>::type*>(ptr);
}

template<class T>
typename exact<T>::type& to_exact(Void<T>& ref) {
  return static_cast<typename exact<T>::type&>(ref);
}

template<class T>
const typename exact<T>::type& to_exact(const Void<T>& ref) {
  return static_cast<const typename exact<T>::type&>(ref);
}



//
//  solve_cast traits
//
//////////////////////////////////////////////////////////////////////


template<template<class> class C,
         class T>
C<T>& solve_cast(C<T>& obj) { return obj; }

template<template<class> class C,
         class T>
const C<T>& solve_cast(const C<T>& obj) { return obj; }

template<template<class, class> class C,
         class T1, class T2 >
C<T1,T2>& solve_cast(C<T1,T2>& obj) { return obj; }

template<template<class, class> class C,
         class T1, class T2 >
const C<T1,T2>& solve_cast(const C<T1,T2>& obj) { return obj; }

template<template<class, class, class> class C,
         class T1, class T2, class T3 >
C<T1,T2,T3>& solve_cast(C<T1,T2,T3>& obj) { return obj; }

template<template<class, class, class> class C,
         class T1, class T2, class T3 >
const C<T1,T2,T3>& solve_cast(const C<T1,T2,T3>& obj) { return obj; }



#endif


final version of our test code (file rec-sol.cc):

#include <iostream>
using std::cout;
using std::endl;

#include "exact_type_vrec.hh"



//
//  recurring hierarchy
//
//////////////////////////////////////////////////////////////////////


template<class I = Bottom>
class A : public Void< A< rec<I> > > { // `rec' inserted
};


template<class U, class I = Bottom>
struct B : public A< rec< B<U,I> > > { // `rec' inserted
  void m() {
    cout << "B::m" << endl;
  }
};



//
//  foo
//
//////////////////////////////////////////////////////////////////////


template<class T>
void foo(A<T>& a) {
  to_exact(a).m();
}



//
//  main
//
//////////////////////////////////////////////////////////////////////


int main()
{
  B<int> b;
  foo(b);
}



Thierry Géraud
Last modified: Fri Jun 22 11:59:17 CEST 2001