Type inference in Visual C++ 2008
Is there开发者_如何转开发 some vendor-specific type inference mechanism in Microsoft Visual C++ 2008, similar to the standardized auto
or decltype
in C++0x?
No, nothing like that, standard nor vendor specific nor addon. You'll have to upgrade to VS2010, it implements auto.
Quoting from a Boost mailing list article by Arkadiy Vertleyb:
God only knows what else can be found inside this compiler if one is willing to dig real deep.
For example, Igor' Chesnokov from RSDN (Russian Software Development Network) has found a way to implement typeof() that does not require registration, and probably has compile-time performance of a native typeof.
How? Apparently, some weird "feature" of Visual C++ allowed him to twick a template body at the moment of instantiation, when additional context is available, thus "registering" classes on the fly, at the moment of taking typeof().
Microsoft-specific "bugfeatures" are generally not in the area of my interests. However I do realize that, on the Microsoft compiler, this might look much more attractive then anything Peder and I have implemented. And even though I realize that this might be a serious competition, I would feel really bad not to mention this here:
http://rsdn.ru/Forum/?mid=1094305
And quoting Igor Chesnokov's code from the page referenced by the quoted link above:
// type_of() evil implementation for VC7
//
// (c) Chez
// mailto:chezu@pisem.net
#include "stdafx.h"
// This file contains:
// 1) type_id(type)
// 2) var_type_id(expersssion)
// 3) type_of(expression)
// IMPLEMENTATION
template<int ID>
class CTypeRegRoot
{
public:
class id2type;
};
template<typename T, int ID>
class CTypeReg : public CTypeRegRoot<ID>
{
public:
class CTypeRegRoot<ID>::id2type // This uses nice VC6-VC7 bugfeature
{
public:
typedef T Type;
};
typedef void Dummy;
};
template<int N>
class CCounter;
// TUnused is required to force compiler to recompile CCountOf class
template<typename TUnused, int NTested = 0>
class CCountOf
{
public:
enum
{
__if_exists(CCounter<NTested>) { count = CCountOf<TUnused, NTested + 1>::count }
__if_not_exists(CCounter<NTested>) { count = NTested }
};
};
template<class TTypeReg, class TUnused, int NValue> // Helper class
class CProvideCounterValue
{
public:
enum { value = NValue };
};
// type_id
#define type_id(type) \
(CProvideCounterValue< \
/*register TYPE--ID*/ typename CTypeReg<type, CCountOf<type >::count>::Dummy, \
/*increment compile-time Counter*/ CCounter<CCountOf<type >::count>, \
/*pass value of Counter*/CCountOf<type >::count \
>::value)
// Lets type_id() be > than 0
class __Increment_type_id { enum { value = type_id(__Increment_type_id) }; };
template<int NSize>
class sized
{
private:
char m_pad[NSize];
};
template<typename T>
typename sized<type_id(T)> VarTypeID(T&);
template<typename T>
typename sized<type_id(const T)> VarTypeID(const T&);
template<typename T>
typename sized<type_id(volatile T)> VarTypeID(volatile T&);
template<typename T>
typename sized<type_id(const volatile T)> VarTypeID(const volatile T&);
// Unfortunatelly, var_type_id() does not recognize references
#define var_type_id(var) \
(sizeof(VarTypeID(var)))
// type_of
#define type_of(expression) \
/* This uses nice VC6-VC7 bugfeature */ \
CTypeRegRoot<var_type_id(expression)>::id2type::Type
// auto_operator
#define auto_operator(arg1, arg2, op) \
type_of(instance(arg1) op instance(arg2)) operator op
// TEST
class A
{
public:
friend static const char* operator +(const A& a, const A& b)
{
return "chijik-pijik";
}
};
template<typename T>
class Plus
{
public:
friend static type_of(T() + T()) operator +(const Plus<T>& a, const Plus<T>& b)
{
return a.m + b.m;
}
T m;
};
int _tmain(int argc, _TCHAR* argv[])
{
Plus<A> a1, a2;
const char* x = a1 + a2;
return 0;
}
Now I haven't tried this code, and, since it uses compiler-specific stuff, do note that it's for MSVC 7.x. So it may or may not work with a later version. Hopefully it does?
Cheers & hth.,
Use BOOST. Or if you don't want to trudge with all of BOOST, here is a snippet that will work with Visual Studio 2008 (but probably no other version):
namespace typeid_detail {
template <int N>
struct encode_counter : encode_counter<N - 1> {};
template <>
struct encode_counter<0> {};
char (*encode_index(...))[5];
// need to default to a larger value than 4, as due to MSVC's ETI errors. (sizeof(int) = 4)
struct msvc_extract_type_default_param {};
template <typename ID, typename T = msvc_extract_type_default_param>
struct msvc_extract_type;
template <typename ID>
struct msvc_extract_type<ID, msvc_extract_type_default_param> {
template <bool>
struct id2type_impl;
typedef id2type_impl<true> id2type;
};
template <typename ID, typename T>
struct msvc_extract_type : msvc_extract_type<ID,msvc_extract_type_default_param> {
template <>
struct id2type_impl<true> { // VC8.0 specific bugfeature
typedef T type;
};
template <bool>
struct id2type_impl;
typedef id2type_impl<true> id2type;
};
template <typename T, typename ID>
struct msvc_register_type : msvc_extract_type<ID, T> {
};
template <int i>
struct int_ {
enum { value = i };
};
template <int ID>
struct msvc_typeid_wrapper {
typedef typename msvc_extract_type<int_<ID> >::id2type id2type;
typedef typename id2type::type type;
};
template <>
struct msvc_typeid_wrapper<1> {
typedef msvc_typeid_wrapper<1> type;
};
// workaround for ETI-bug for VC6 and VC7
template <>
struct msvc_typeid_wrapper<4> {
typedef msvc_typeid_wrapper<4> type;
};
// workaround for ETI-bug for VC7.1
#define TYPEOF_INDEX(T) (sizeof(*encode_index((encode_counter<405/*1005*/>*)0))) // this needs to be lower for VS 2008, otherwise causes too deep templates
#define TYPEOF_NEXT_INDEX(next) friend char (*encode_index(encode_counter<next>*))[next];
template <typename T>
struct encode_type {
static const unsigned value = TYPEOF_INDEX(T);
// get the next available compile time constants index
typedef typename msvc_register_type<T,int_<value> >::id2type type;
// instantiate the template
static const unsigned next = value + 1;
// set the next compile time constants index
TYPEOF_NEXT_INDEX(next);
// increment the compile time constant (only needed when extensions are not active)
};
template <class T>
struct sizer {
typedef char(*type)[encode_type<T>::value];
};
template <typename T> typename sizer<T>::type encode_start(T const&);
// a function that converts a value to size-encoded type (not implemented, only needed for type inference)
template <typename Organizer, typename T>
msvc_register_type<T, Organizer> typeof_register_type(const T&, Organizer* = 0);
} // ~typeid_detail
#define type_of(expr) \
typeid_detail::msvc_typeid_wrapper<sizeof(*typeid_detail::encode_start(expr))>::type
And use e.g. as:
int x = 123;
float y = 456.0f;
typedef type_of(x+y) int_plus_float;
int_plus_float value = x + y;
And of course refer to BOOST license when using this.
精彩评论