2

我正在设计一个“取消引用”类,为了好玩。

我写了一些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,它是被解引用到 2 级指针的迭代器,因此具有 3 级可解引用性。

在这里,我想知道T编译时任意类型的“可取消引用”的最大级别。

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

我认为这类似于在编译时生成一个序列:模板元组 - 在每个元素上调用一个函数 ,但我无法画出具体的图片。

这是我尝试过的:

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 类的成员)出了什么问题?

4

3 回答 3

3

这是一个直接使用 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 };
};

在 Wandbox 上现场观看

于 2020-09-08T09:18:25.173 回答
1

我不知道您的模板示例出了什么问题,但这是使用递归 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
}
于 2020-09-08T09:20:17.933 回答
1

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

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

由于结构级 SFINAE 检查失败,我采用了另一种方法,根据答案从重载函数中推导出返回类型: linkauto->decltype

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

现在我有了一个强大的可解引用性检查器,剩下的部分就变得容易多了。

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 中测试了上面的代码,没有出现错误。

于 2020-09-10T19:35:47.813 回答