开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜