如何使用模板找到参数 T 的最大可取消引用级别

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

我正在设计一个 “解引用器” class,只是为了好玩。

我写了一些 structs 和 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>>;

假设有一个类型为T = std::vector<int**>::iterator的变量,它是解引用为二级指针的迭代器,因此具有三级解引用能力。

在这里,我想知道任意类型 T 编译时 .

的最大“解引用能力”
std::cout << deref_level<std::vector<int**>::iterator>::max << std::endl; // this should prints 3

我认为这类似于在编译时生成一个序列:Template tuple - calling a function on each element ,但是我画不出来具体的图

这是我试过的方法:

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;

但它不起作用...(编译器说 max 不是 tje class 的成员)出了什么问题?

下面是直接使用SFINAE的递归实现:

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 };
};

See it live on Wandbox

我不知道你的模板示例出了什么问题,但这是一个使用递归 consteval 函数的实现:

#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
}

经过几天的工作,我能够编写出在 MSVC13 中不会导致错误的代码。

首先,我需要一个健壮的模块来检查类型的解引用能力

由于 struct-level SFINAE 检查失败,我采用了另一种方法,从 重载函数 auto->decltype 表达式中推导出 return 类型,基于答案: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;
};

现在我有一个健壮的dereferenceability-checker,剩下的部分变得容易多了。

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;
}

我在 Visual Studio 2013 年测试了上面的代码,没有发生错误。