Topic: Poor man's typeof( ) implementation
Author: bparker@mailbox.uq.edu.au (Brian Parker)
Date: 1997/11/10 Raw View
For what it's worth, following this post is a rewrite of the typeof( )
code using only portable constructs (it doesn't use non-portable
typeid( ) behaviour) and which works with polymorphic types. As
before, this code is really only good for playing around with
typeof()- hopefully a full implementation of typeof( ) will become a
common (non-standard) compiler extension.
,Brian Parker.
---8<----------------------------------------------------------------------------------------------
// Portable (limited) typeof( ) emulation.
// Its limitation is that any type used with it must be
// preregistered using the macro REGISTER_TYPEx- this effectively
// renders this implementation useless for any purpose but
// experimentation with typeof( ).
#include <iostream>
using namespace std;
class ErrorNotRegistered {};
// Template to look up a unique ID for a type.
// (by default, use class member "id" to get unique ID)
template<class T>
struct GetID {
enum {id = T::id};
};
// Template to lookup the associated type given a unique ID,
template<int id>
struct GetType {
typedef ErrorNotRegistered type;
};
// Register a class that supplies a unique ID using a member "id"
#define REGISTER_TYPE(CLASS) \
template<> \
struct GetType<GetID<CLASS >::id > { \
typedef CLASS type; \
}; \
// Register a class and also supply a unique ID
#define REGISTER_TYPE2(CLASS, ID) \
template<> \
struct GetID<CLASS > { \
enum {id = ID}; \
}; \
REGISTER_TYPE(CLASS) \
// The unique ID is encoded as the size of a struct
// so that sizeof() can be used to avoid evaluating the expression.
template<class T>
struct Encode_ID_as_size {
char buf[GetID<T >::id];
};
template<class T>
Encode_ID_as_size<T> EncodeID(const T& t)
{
return Encode_ID_as_size<T>();
}
#define typeof(exp) GetType<sizeof(EncodeID(exp))>::type
// Helper macro to handle classes without default constructors.
// (expr should be defined as follows, but VC++ 5.0 doesn't like it)
//#define expr(A) (*(A *)0)
#define expr(A) (A())
// register some built-in types
REGISTER_TYPE2(float, 5)
REGISTER_TYPE2(double, 6)
// an example function using typeof( )
template<class A, class B>
typeof(expr(A) * expr(B)) MyFunc(A a, B b)
{
return a * b;
}
template<class T, int ID = 1234>
struct MyClass {
MyClass(T t):f(t) {}
T f;
enum {id = ID};
};
REGISTER_TYPE(MyClass<double>)
template<class T>
MyClass<T> operator*(const MyClass<T>& t1, const MyClass<T>& t2)
{
return MyClass<T>(t1.f * t2.f);
}
int main()
{
float d1 = 3.0;
float d2 = 4.0;
typeof(d1 * d2) g1 = d1 * d2;
cout << g1 << '\n';
typeof(MyFunc(d1, d2)) g2 = MyFunc(d1, d2);
cout << g2 << '\n';
MyClass<double> c1 = 4.5;
MyClass<double> c2 = 2.0;
typeof(c1 * c2) g3 = c1 * c2;
cout << g3.f << '\n';
}
---end----------------------------
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: bparker@mailbox.uq.edu.au (Brian Parker)
Date: 1997/10/29 Raw View
On 29 Oct 97 05:27:53 GMT, I bparker@mailbox.uq.edu.au (Brian Parker)
wrote:
>...
>This implementation is more for its novelty value and experimentation
>than for any serious use as it has a number of major limitations-
>
>(1) It only works with non-polymorphic types. If a class has a virtual
>function then typeid( ) switches to run-time behaviour; in that case,
>this code will give a compile-time error.
>...
Actually, it has just occurred to me that by modifying the code to use
pointers throughout, the code should also work for polymorphic types
(because pointers themselves are always non-polymorphic).
The modified code follows this post.
I say "should work" because VC++ 5.0 gives an internal error when this
new code is used on polymorphic types .
Can anyone get this code to work on another compiler?
> (3) It relies on implementation-defined behaviour- in particular it
> assumes that typeid returns a pointer to a different type_info object
> for different types, which is not guaranteed by the CD2.
I no longer think that that is a problem as the type_info's for
different types clearly must be different, and within a single
compilation unit it would be truly perverse for an implementation to
return different type_infos for the same type- in fact, perhaps the
standard could specify this?.
> It also
> assumes that typeid is evaluated at compile-time for non-polymorphic
> types, which I believe is the intent of the draft standard and
> certainly is what VC++ 5.0 does (can anyone clarify this?)
On re- reading the CD2, it seems to me that this issue is not properly
specified- I think the standard should explicitly state that for
non-polymorphic types typeid is a constant expression. As it stands,
it only hints at this.
Whilst this is still a god-awful hack, it would almost be usable if
the new code changes worked, and would ease portablity to compilers
that provided a full implementation of typeof( ).
I note that the Gnu C compiler supports this extension; has typeof()
been considered for the upcoming C standard revision?
The updated code follows-
--8<----------------------------------------------------------------------------------------
// Emulate typeof for non-polymorphic types
// Compiled under Visual C++ v 5.0
template<class T>
T** kludge(const T&) {return (T**)0;}
#define typeof(X) Type_lookup_trait<&typeid(kludge(X) )>::type
class ERROR_TYPE_NOT_REGISTERED {};
template<const type_info*>
struct Type_lookup_trait {
typedef ERROR_TYPE_NOT_REGISTERED type;
};
#define REGISTER_TYPE(X) \
template<> \
struct Type_lookup_trait<&typeid(X **)> \
{ \
typedef X type; \
}; \
//----------------------------------------------------
// remaining code unchanged...
,Brian Parker
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: bparker@mailbox.uq.edu.au (Brian Parker)
Date: 1997/10/29 Raw View
The following is a partial implementation of typeof( ) based on
typeid( ) (which, for non-polymorphic types does not evaluate its
expression and generates its result at compile-time).
This implementation is more for its novelty value and experimentation
than for any serious use as it has a number of major limitations-
(1) It only works with non-polymorphic types. If a class has a virtual
function then typeid( ) switches to run-time behaviour; in that case,
this code will give a compile-time error.
(2) Every type used with typeof( ) must be registered once using the
REGISTER_TYPE macro. This largely defeats the purpose of typeof( ) in
template code, though it does beat adding a traits class for every
operator and permutation of type promotions.
(3) It relies on implementation-defined behaviour- in particular it
assumes that typeid returns a pointer to a different type_info object
for different types, which is not guaranteed by the CD2. It also
assumes that typeid is evaluated at compile-time for non-polymorphic
types, which I believe is the intent of the draft standard and
certainly is what VC++ 5.0 does (can anyone clarify this?)
The most interesting thing about the following code snippet is that it
indicates how trivial a complete implementation of typeof( ) would
be-- the bulk of the implementation is there already.
The more I think about typeof( ) the more I realise just how important
it is for generic functions. As others have pointed out in this
newsgroup, with general mixed-mode arguments a template function has
no other mechanism to discover the required return type, except by
using a combinatorial explosion of traits classes; I know that I could
get rid of a lot of traits classes in my code if it were available.
It's a shame typeof( ) didn't make it into this standard round, IMHO.
Anyway, the code follows-
--8<--------------------------------------------------------------------------------------------
#include <iostream>
#include <typeinfo>
//---------------------------------------------------
// Emulate typeof for non-polymorphic types
// Compiled under Visual C++ v 5.0
#define typeof(X) Type_lookup_trait<&typeid(X)>::type
class ERROR_TYPE_NOT_REGISTERED {};
// use address of returned type_info to index into a traits class
template<const type_info*>
struct Type_lookup_trait {
typedef ERROR_TYPE_NOT_REGISTERED type;
};
// specialise traits class for every type used
#define REGISTER_TYPE(X) \
template<> \
struct Type_lookup_trait<&typeid(X)> \
{ \
typedef X type; \
}; \
//----------------------------------------------------
// Define example classes
class C{
public:
void f();
C(int) {}
C() {}
};
class D{
public:
D() {}
D(const C& a) {} // promote from C to D
};
// example operation on C's and D's
D operator*(const D& lhs, const D& rhs)
{
return D();
}
// need to register types- yeech!
REGISTER_TYPE(double)
REGISTER_TYPE(float)
REGISTER_TYPE(int)
REGISTER_TYPE(C)
REGISTER_TYPE(D)
// An example function using typeof
template<class A, class B>
typeof(A() * B()) mult(A a, B b)
{
typeof(a * b) r = a * b;
std::cout << typeid(r).name() << '\n'; // debug output
return r;
}
int main()
{
int i = 1;
double f = 2.0;
double fr;
fr = mult(i, f); // prints "double"
C c;
D d;
D r;
r = mult(c, d); // prints "class D"
return 0;
}
--------------------------------------------------------------------
,Brian Parker
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]