// This piece of magic brought to you by: // http://www.nedproductions.biz/blog/ // implementing-typeof-in-microsofts-c-compiler #ifndef MSVC_TYPEOF_H #define MSVC_TYPEOF_H #if defined(_MSC_VER) && _MSC_VER>=1400 namespace msvc_typeof_impl { /* This is a fusion of Igor Chesnokov's method (http://rsdn.ru/forum/src/1094305.aspx) and Steven Watanabe's method (http://lists.boost.org/Archives/boost/2006/12/115006.php) How it works: C++ allows template type inference for templated function parameters but nothing else. What we do is to pass the expression sent to typeof() into the templated function vartypeID() as its parameter, thus extracting its type. The big problem traditionally now is how to get that type out of the vartypeID() instance, and here's how we do it: 1. unique_type_id() returns a monotonically increasing integer for every unique type passed to it during this compilation unit. It also specialises an instance of msvc_extract_type::id2type_impl. 2. vartypeID() returns a sized for the type where sizeof(sized)==unique_type_id. We vector through sized as a means of returning the unique_type_id at compile time rather than runtime. 3. msvc_extract_type then extracts the type by using a bug in MSVC to reselect the specialised child type (id2type_impl) from within the specialisation of itself originally performed by the above instance of unique_type_id. This bug works because when MSVC calculated the signature of the specialised msvc_extract_type::id2type_impl, it does not include the value of type in the signature of id2type_impl. Therefore when we reselect msvc_extract_type::id2type_impl it erroneously returns the one already in its list of instantiated types rather than correctly generating a newly specialised msvc_extract_type::id2type_impl This bug allows the impossible and gives us a working typeof() in MSVC. Hopefully Microsoft won't fix this bug until they implement a native typeof. */ struct msvc_extract_type_default_param {}; template struct msvc_extract_type; template struct msvc_extract_type { template struct id2type_impl; typedef id2type_impl id2type; }; template struct msvc_extract_type : msvc_extract_type { template<> struct id2type_impl //VC8.0 specific bugfeature { typedef T type; }; template struct id2type_impl; typedef id2type_impl id2type; }; template class CCounter; // TUnused is required to force compiler to recompile CCountOf class template struct CCountOf { enum { __if_exists(CCounter) { count = CCountOf::count } __if_not_exists(CCounter) { count = NTested } }; }; template struct CProvideCounterValue { enum { value = NValue }; }; // type_id #define unique_type_id(type) \ (CProvideCounterValue< \ /*register TYPE--ID*/ typename msvc_extract_type::count, type>::id2type, \ /*increment compile-time Counter*/ CCounter::count>, \ /*pass value of Counter*/CCountOf::count \ >::value) // Lets type_id() be > than 0 class __Increment_type_id { enum { value = unique_type_id(__Increment_type_id) }; }; // vartypeID() returns a type with sizeof(type_id) template class sized { char m_pad[NSize]; }; template typename sized vartypeID(T&); template typename sized vartypeID(const T&); template typename sized vartypeID(volatile T&); template typename sized vartypeID(const volatile T&); } #define typeof(expression) msvc_typeof_impl::msvc_extract_type::id2type::type #endif #endif