获取 CRTP 继承链中最深的类

Get deepest class in CRTP inheritance chain

本文关键字:CRTP 继承 获取      更新时间:2023-10-16

我想知道如何解决以下问题(C++17(:假设有几个模板类,它们以类似 CRTP 的方式相互继承(仅限单个继承(。对于给定的实例化模板基类,在继承链中查找离它最远的类。

我最初认为这应该很容易,但无法做到这一点。

为了简化起见,假设每个根和每个中间类在其public区域中都有using DerivedT = Derived

例:

template <class T>
struct GetDeepest {
    using Type = ...;
};
template <class T>
struct A {
    using DerivedT = T;
};
template <class T>
struct B : public A<B<T>> {
    using DerivedT = T;
};
struct C : B<C> {
};
struct D : A<D> {
};
GetDeepest<A<D>>::Type == D;
GetDeepest<B<C>>::Type == C;
GetDeepest<A<B<C>>>::Type == C;
...

我尝试过的第一个实现:

template <class T>
struct GetDeepest {
    template <class Test, class = typename Test::DerivedT>
    static std::true_type Helper(const Test&);
    static std::false_type Helper(...);
    using HelperType = decltype(Helper(std::declval<T>()));
    using Type = std::conditional_t<std::is_same_v<std::true_type, HelperType>,
                    GetDeepest<typename T::DerivedT>::Type,
                    T>;
};

我尝试过的第二个实现:

template <class T>
struct HasNext {
    template <class Test, class = typename Test::DerivedT>
    static std::true_type Helper(const Test&);
    static std::false_type Helper(...);
    using HelperType = decltype(Helper(std::declval<T>()));
    static const bool value = std::is_same_v<std::true_type, HelperType>;
};
template <class T>
auto GetDeepestHelper(const T& val) {
    if constexpr(HasNext<T>::value) {
        return GetDeepestHelper(std::declval<typename T::DerivedT>());
    } else {
        return val;
    }
}
template <class T>
struct GetDeepest {
    using Type = decltype(GetDeepestLevelHelper(std::declval<T>()));
};

它们都不编译。

第一个 -- 因为语句 using Type = ...GetDeepest<T>类型不完整,第二个是因为递归调用以 auto 作为返回类型的函数。

甚至可以实现具有此类属性GetDeepest<T>类吗?现在我很好奇,即使这可能不是实现我想要的最好方法。

谢谢!

我不确定我是否完全理解这个问题,所以请随时在评论中问我。

但我认为这应该有效:

#include <type_traits>
template<typename T>
struct GetDeepest
{
    using Type = T;
};
template<template<typename> class DT, typename T>
struct GetDeepest<DT<T>>
{
    using Type = typename GetDeepest<T>::Type;
};
template <class T>
struct A {
    using DerivedT = T;
};
template <class T>
struct B : public A<B<T>> {
    using DerivedT = T;
};
struct C : B<C> {
};
struct D : A<D> {
};
int main()
{
    static_assert(std::is_same<GetDeepest<A<D>>::Type, D>::value);
    static_assert(std::is_same<GetDeepest<B<C>>::Type, C>::value);
    static_assert(std::is_same<GetDeepest<A<B<C>>>::Type, C>::value);
}