gpt4 book ai didi

c++ - 遍历带有非类型模板参数的模板基类的CRTP继承链

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:02:45 24 4
gpt4 key购买 nike

这是对问题的跟进: Get deepest class in CRTP inheritance chain

以下代码找到第一个模板参数,该参数派生自模板 CRTP 基类的给定实例并可能递归(这只是对上一个问题的更通用的解决方案):

// Find the first type that matches the predicate
template <template <class T> class Predicate, class... Args>
struct FindFirstMatching {
using Type = ...; // Default NullType
static const bool has_match = ...; // whether there has been a match
};

// Utility class to get the deepest class in CRTP inheritance chain
template <typename T>
struct GetDeepest {
using Type = T;
};

template <template <class...> class DT, class... T>
struct GetDeepest<DT<T...>> {
template <class CLS>
struct Predicate {
static const bool value = std::is_base_of_v<DT<T...>, CLS>;
};

static const bool HasCRTPDerived = FindFirstMatching<Predicate, T...>::has_match;
using DerivedT = typename FindFirstMatching<Predicate, T...>::Type;

using Type = std::conditional_t<HasCRTPDerived,
typename GetDeepest<DerivedT>::Type,
DT<T...>>;
};

所以我想 DT<T...>在 CRTP 基类的实例化中。问题是,它也可能有非类型模板参数,我不知道如何以最一般的方式处理它。

例如:

template <class DerivedT, bool param>
class ParamBase {
};

class Derived : public ParamBase<Derived, false> {
};

GetDeepest<ParamBase<Derived, false>>::Type == ParamBase<Derived, false>
// instead of desirable
// GetDeepest<ParamBase<Derived, false>>::Type == Derived

一种可能的解决方案是使用类似类型标签的东西来代替非类型模板参数:

template <class T>
A {};

A<TrueType>;
A<FalseType>;

代替

template <bool param>
A{};

但我认为这不是一个好的解决方案。

我也可以使用类似 template <class..., auto...> DT 的东西,但这会迫使我在参数列表的末尾使用非类型模板参数。这是可以接受的,但问题是如果我忘记它,它会灾难性地失败。

如果我能这样写就好了:

template <typename T>
struct GetDeepest {
static_assert(!IsTemplateInstantiation<T>::value);
using Type = T;
};

我的问题是:

如何将代码泛化为可能的非类型模板参数?

我如何实现 IsTemplateInstantiantion

编辑:好像不能写template <class..., auto...>在 C++17 中,所以后者不是一个选项。

最佳答案

我会回到您在原始问题中提出的第一个解决方案(假设每个非叶类模板声明一个 DerivedT 类型,为其派生类起别名)。让我们记忆一下您的第一个实现:

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

您似乎遗漏了叶类也继承了 DerivedT来自其基类的成员类型声明。这意味着调用 Helper(std::declval<D>())将调用返回 std::true_type 的重载.换句话说:

template <typename T>
struct A {
using DerivedT = T;
};

struct D : A<D> {
using DerivedT = D; // inherited from A<D>
};

因此,在实例化 GetDeepest<D> 时, GetDeepest<D>::Type结束别名 GetDeepest<D::DerivedT>::Type这是GetDeepest<D>::Type并且编译器提示 GetDeepest<D>::Type不是一个完整的类型,因为它试图成为自己的别名!

因此,我们需要改变我们的递归停止条件。想到的一种解决方案是:

A type T is a leaf-node in the CRTP hierarchy iff its DerivedT member type is an alias to T

而且实现非常简单:

#include <type_traits>

// a type T is a leaf-node in the CRTP hierarchy iff:
// its DerivedT member type is an alias to T
template <typename T>
inline constexpr bool is_leaf_type_v = std::is_same_v<T, typename T::DerivedT>;

// general case:
// GetDeepest<T>::Type is an alias to GetDeepest<T::DerivedT>::Type
template <typename T, typename = void>
struct GetDeepest {
using Type = typename GetDeepest<typename T::DerivedT>::Type;
};

// base case: when T is a leaf type
// We have reached a leaf node => GetDeepest<T>::Type is an alias to T
template <typename T>
struct GetDeepest<T, std::enable_if_t<is_leaf_type<T> > > {
using Type = T;
};

// tests
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);
}

此方法不需要您在 GetDeepest 中为您的类声明模板参数(如果我理解正确的话,这是你第二个问题的主要问题)。我认为你也可以实现 FindFirstMathing以类似的方式。

我也会远离依赖 IsTemplateInstantiation查询类型是否是 CRTP 层次结构中的叶类型(即使可以实现)。想到的一个反例是 Eigen::Matrix<int, 3, 3>这是一个继承自 Eigen::PlainObjectBase<Eigen::Matrix<int, 3, 3>> 的类模板 CRTP 叶类型.类和类模板实例化之间的这种区别不是您要找的。

关于c++ - 遍历带有非类型模板参数的模板基类的CRTP继承链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56569771/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com