c++c++11visual-c++-2013

How to find maximum dereferenceable-level of the parameter T using template


I am designing a "dereferencer" class, for fun.

I wrote some structs and aliass :

template <class _T>
using deref_type = decltype(*std::declval<_T>());

template <class _T, class _SFINAE>
struct is_derefable : std::false_type {};

template <class _T>
struct is_derefable< _T, deref_type<_T> > : std::true_type
{
    using return_type = deref_type<_T>;
};

template<class _T>
using check_derefable = is_derefable<T, deref_type<T>>;

and let's say that there is a variable with type T = std::vector<int**>::iterator, which is the iterator dereferenced into a level-2 pointer, thus has a 3-level dereferenceability.

Here, I want to know the maximum level of "dereferenceability" of an arbitrary type T, at the compile-time.

std::cout << deref_level<std::vector<int**>::iterator>::max << std::endl; // this should prints 3

I thought that it would be way similar to generating a sequence at the compile-time: Template tuple - calling a function on each element , but I can't draw a concrete picture of it.

Here are what I've tried:

template<class _TF, class _T>
struct derefability {};

template<int _N, class _derefability>
struct deref_level;

template<int _N, class _T>
struct deref_level<_N, derefability<std::false_type, _T>>
{
    static const int max = _N;
};

template<int _N, class _T>
struct deref_level<_N, derefability<std::true_type, _T>> : 
    deref_level<_N + 1, derefability<typename check_derefable<deref_type<_T>>::type, deref_type<_T>>>{};

deref_level<0, derefability<check_derefable<T>::type, T>::max;

but it does not work...(compiler says that max is not a member of tje class) What went wrong?


Solution

  • After a few days of work, I was able to write code that works without causing an error in MSVC13.

    First of all, I needed a robust module to check the dereferenceability of the type.

    Since the struct-level SFINAE check fails, I took another method that deduces the return type from overloaded functions with auto->decltype expression, based on the answer: link

    template<class T>
    struct is_dereferenceable
    {
    private:
        template<class _type>
        struct dereferenceable : std::true_type
        {
            using return_type = _type;
        };
    
        struct illegal_indirection : std::false_type
        {
            using return_type = void*;
        };
    
        template<class _type>
        static auto dereference(int)->dereferenceable<
            decltype(*std::declval<_type>())>;
    
        template<class>
        static auto dereference(bool)->illegal_indirection;
    
        using dereferenced_result = decltype(dereference<T>(0));
    
    public:
        using return_type = typename dereferenced_result::return_type;
        static const bool value = dereferenced_result::value;
    };
    

    Now I have a robust dereferenceability-checker, the remaining part becomes far easy.

    template< class T,
        class D = typename is_dereferenceable<T>::return_type >
    struct dereferenceability;
    
    template< class T >
    struct dereferenceability<T, void*>
    {
        using level = std::integral_constant<int, 0>;
    };
    
    template< class T, class D >
    struct dereferenceability<T, D&>
    {
        using level = std::integral_constant<int, dereferenceability<D>::level::value + 1>;
    };
    
    int main()
    {
        static_assert(dereferenceability<int>::level::value == 0, "something went wrong");
        static_assert(dereferenceability<int****>::iterator>::level::value == 4, "something went wrong");
        return 0;
    }
    
    

    I've tested codes above in Visual Studio 2013, and no error occured.