Search code examples
c++dereference

How to determine if a type is dereferenceable in C++03?


In C++03, how do I determine if a type T is dereferenceable?
By which I mean, how do I statically determine if *t would be a valid expression for t of type T?

My attempt:

template<bool B, class T = void> struct enable_if { };
template<class T> struct enable_if<true, T> { typedef T type; };

unsigned char (&helper(void const *))[2];
template<class T>
typename enable_if<
    !!sizeof(**static_cast<T *>(NULL)),
    unsigned char
>::type helper(T *);

template<class T>
struct is_dereferenceable
{ static bool const value = sizeof(helper(static_cast<T *>(NULL))) == 1; };

struct Test
{
    int *operator *();
    void operator *() const;
private:
    Test(Test const &);
};

int main()
{
    std::cout << is_dereferenceable<int *>::value;       // should be true
    std::cout << is_dereferenceable<void *>::value;      // should be false
    std::cout << is_dereferenceable<Test>::value;        // should be true
    std::cout << is_dereferenceable<Test const>::value;  // should be false
}

It works on GCC (prints 1010) but crashes and burns on VC++ (1110) and Clang (1111).


Solution

  • #include <boost\type_traits\remove_cv.hpp>
    #include <boost\type_traits\is_same.hpp>
    #include <boost\type_traits\remove_pointer.hpp>
    #include <boost\type_traits\is_arithmetic.hpp>
    #include <boost\utility\enable_if.hpp>
    
    namespace detail
    {
        struct tag 
        { 
            template < typename _T > 
            tag(const _T &); 
        };
    
        // This operator will be used if there is no 'real' operator
        tag operator*(const tag &);
    
        // This is need in case of operator * return type is void
        tag operator,(tag, int);  
    
        unsigned char (&helper(tag))[2];
    
        template < typename _T >
        unsigned char helper(const _T &);
    
        template < typename _T, typename _Enable = void >
        struct traits
        {
            static const bool value = (sizeof(helper(((**static_cast <_T*>(NULL)), 0))) == 1);
        };
    
        // specialization for void pointers
        template < typename _T >
        struct traits < _T,
            typename boost::enable_if < typename boost::is_same < typename boost::remove_cv < typename boost::remove_pointer < _T > ::type > ::type, void > > ::type >
        {
            static const bool value = false;
        };
    
        // specialization for arithmetic types
        template < typename _T >
        struct traits < _T,
            typename boost::enable_if < typename boost::is_arithmetic < typename boost::remove_cv < _T > ::type > > ::type >
        {
            static const bool value = false;
        };
    }
    
    template < typename _T > 
    struct is_dereferenceable :
        public detail::traits < _T >
    { };
    

    I have tested it in msvs 2008