Reputation: 111
I am designing a "dereferencer" class, for fun.
I wrote some struct
s and alias
s :
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?
Upvotes: 2
Views: 118
Reputation: 111
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.
Upvotes: 1
Reputation: 3107
I don't know what went wrong with your template example, but here's an implementation using a recursive consteval function:
#include <type_traits>
template<typename T, int N = 0>
consteval int deref_level()
{
if constexpr (std::is_pointer<T>::value) {
typedef typename std::remove_pointer<T>::type U;
return deref_level<U, N + 1>();
} else {
return N;
}
}
int main() {
return deref_level<int****>(); // Returns 4
}
Upvotes: 1
Reputation: 63114
Here is a recursive implementation using SFINAE directly:
template <class T, class = void>
struct deref_level {
enum : std::size_t { value = 0 };
};
template <class T>
struct deref_level<T, decltype(void(*std::declval<T const &>()))> {
enum : std::size_t { value = deref_level<decltype(*std::declval<T const &>())>::value + 1 };
};
Upvotes: 3