Black Moses Black Moses - 3 months ago 6
C++ Question

Get pointer level from type rather than from variable

I try to make it possible to display pointer depth as integer number of asterisks - for example

int***
would be
3
. But instead of calculating it from type, I wrote code that requires that every level of pointer have to be properly initialized. Here is what I tried:

#include <iostream>
#include <utility>

// no pointers involved
template <class T>
std::size_t get_pointer_level(T)
{
return 0;
}

// final value reached, returning depth
template <class T>
std::size_t get_pointer_level(std::pair<std::size_t, T> arg)
{
return arg.first;
}

// function that accummulates depth
template <class T>
auto get_pointer_level(std::pair<std::size_t, T*> arg)
{
return get_pointer_level(std::make_pair(arg.first+1, *arg.second));
}

// initial function called for pointer argument
template <class T>
auto get_pointer_level(T* arg)
{
return get_pointer_level(std::make_pair(std::size_t(1), *arg));
}


int main(void)
{
int a = 10;
auto b = &a; //int*
auto c = &b; //int**
auto d = &c; //int***
auto e = &d; //int****
std::cout << get_pointer_level(e) << std::endl; //4
}


I'm pretty sure that it's very possible to make it work just with type alone. I imagine syntax would be something like that:

get_pointer_level<int****>::value


Any ideas?




EDIT:
Thanks for the solution! Here is final functionality that I wanted to accomplish:

template <std::size_t A, std::size_t B>
struct is_smaller
{
enum {value = (A < B)? 1 : 0};
};
template<std::size_t Target, typename T, std::size_t Actual = get_pointer_level<T>::value>
T value_at_level(T pointer)
{
static_assert(Actual==Target, "Invalid target level!");
return pointer;
}

template<std::size_t Target, typename T, std::size_t Actual = get_pointer_level<T*>::value,
typename = std::enable_if<is_smaller<Target, Actual>::value>::type>
auto value_at_level(T* pointer)
{
return value_at_level<Target>(*pointer);
}

int main()
{
int a = 5;
auto b = &a; //int*
auto c = &b; //int**
auto d = &c; //int***
auto e = &d; //int****

std::cout << "int from int****: " << value_at_level<0>(e) << std::endl; //ok
std::cout << "int* from int***: " << value_at_level<1>(d) << std::endl; //ok
std::cout << "int** from int**: " << value_at_level<2>(c) << std::endl; //ok
std::cout << "int*** from int*: " << value_at_level<3>(b) << std::endl; //error
std::cout << "int**** from int: " << value_at_level<5>(a) << std::endl; //error
}

Answer

An exercise in partial specialization:

#include <cstddef>

template<typename T, std::size_t S>
struct get_pointer_level_impl
{
    static const std::size_t value = S;
};

template<typename T, std::size_t S>
struct get_pointer_level_impl<T*, S> : get_pointer_level_impl<T, S+1>
{

};

template<typename T>
struct get_pointer_level : get_pointer_level_impl<T, 0>
{

};

#include <iostream>

int main()
{
    std::cout << get_pointer_level<int>::value << "\n";
    std::cout << get_pointer_level<int*>::value << "\n";
    std::cout << get_pointer_level<int**>::value << "\n";
    std::cout << get_pointer_level<int***>::value << "\n";
}

Output:

0
1
2
3
Comments