// Portable "typeof" operator and test program.
//
// Written by Bill Gibbons 2/18/2000
//
// This example uses function overloading and template specialization
// to implement a restricted form of the "typeof" operator.
//
// Each type for which "typeof" must work must be registered with
// the REGISTER_TYPEOF macro, which generates the required template
// specialization and overloaded function declaration.
//
// An ordinal 1..n is assigned to each type and used to pass type
// information by encoding the type as a number (in an array size)
// and using "sizeof" to extract the value as a constant.
//==================== The "typeof" machinery ====================

template<int N> struct typeof_class; // no def’n, only specializations
template<class T> struct WrapType { typedef T U; };

#define REGISTER_TYPEOF(N,T) \
    template<> struct typeof_class<N> { typedef WrapType<T>::U V; }; \
    char (*typeof_fct(const WrapType<T>::U &))[N];

#define typeof(x) typeof_class<sizeof(*typeof_fct(x))>::V

//======== Registration of types to be used with "typeof" ========

REGISTER_TYPEOF( 1, char )
REGISTER_TYPEOF( 2, signed char )
REGISTER_TYPEOF( 3, unsigned char )
REGISTER_TYPEOF( 4, short )
REGISTER_TYPEOF( 5, unsigned short )
REGISTER_TYPEOF( 6, int )
REGISTER_TYPEOF( 7, unsigned int )
REGISTER_TYPEOF( 8, long )
REGISTER_TYPEOF( 9, unsigned long )
/* REGISTER_TYPEOF( 10, long long ) - may be unknown type */
/* REGISTER_TYPEOF( 11, unsigned long long ) - may be unknown type */
REGISTER_TYPEOF( 12, float )
REGISTER_TYPEOF( 13, double )
/* REGISTER_TYPEOF( 14, wchar_t ) - may be unknown type */
REGISTER_TYPEOF( 15, int (*)() )

//========================= Test program =========================

#include <iostream.h>
#include <typeinfo.h>

int main()
{
   short a;
    long b;
    typeof(a) c;
    typeof(b) d;
    typeof(1.0) e;
    typeof(main) f;

    cout << "c is " << typeid(c).name() << '\n';
    cout << "d is " << typeid(d).name() << '\n';
    cout << "e is " << typeid(e).name() << '\n';
    cout << "f is " << typeid(f).name() << '\n';

    return 0;

}