- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
这是对问题的跟进: 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 itsDerivedT
member type is an alias toT
而且实现非常简单:
#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/
我目前正在实现一个通用事件类。事件处理程序有一个发送者参数和可变数量的事件参数。所以事件类的声明如下: template class event; 为了允许某些实现细节,我需要事件的 CRTP,如下所
我需要实现对实现相同接口(interface)的对象 vector 的高效访问。直到现在,我一直在使用带有虚函数的继承:接口(interface)被定义为具有纯虚函数的抽象类,每个对象类都实现了虚函数
在CRTP ,基类可以使用派生类的函数和变量。但是,派生类的类型不能直接被基类使用,见下面代码: #include template class A { public: //using S
我创建了一个模板类,只要发生实例化,它就会触发运行时文本输出: template struct verbose { verbose() { std::cout str
假设我有一个用于矩阵的 CRTP 模板类 template class MatrixBase{ private: //... public: Derived some_function
我已经阅读了很多关于 Curiously Recurring Template Pattern 的帖子而且我仍然不明白为什么我不想只使用模板编程来使用它。 下面是一个从维基百科稍作修改的例子: tem
请帮我解决以下问题: 我有一个类声明为: template class Rim : /* Derive from GenericComponent Design perspective u
有没有办法从 CRTP 基类查询派生类的内容,与 SFINAE 一起使用来启用或禁用基类方法? 我想要完成的可能如下所示: template struct base { struct foo
我有兴趣了解 CRTP。我想为引擎实现一个组件系统,我不想访问组件统一风格 GetComponent("withThisName"); 而是在编译时(虚幻风格) GetComponent(); 虽然实
让我们考虑一个用于打印派生类的 CRTP 模板类 Print: template struct Print { auto print() const -> void; auto se
最近我一直在摆弄模板并偶然发现了以下问题。我正在像这样实现 CRTP 模式: template struct protocol_object { ... }; struct data_obje
我正在尝试在固定大小的缓冲区中构建一条消息,我的图书馆的用户会在其中提供一些数据。我曾经通过给用户一个指向缓冲区的指针并让他们写入它,并通过引用他们写入的字节数来设置一个 size_t 参数来做到这一
我刚刚遇到 CRTP 的问题,我不能在基类和派生类中使用相同的方法名称(具有不同的签名)。重现此问题的示例如下: template struct Base { void foo(){}
考虑以下代码: #include #include #include struct BaseClass { static int identifier() { stati
我有一个纯虚类接口(interface): class Interface { public: virtual ~Interface() noexcept; virtual voi
任何人都可以向我解释为什么 base::blah(string str) 的签名必须是一个字符串而不是引用一个字符串。如果它是一个字符串,编译器会出现以下错误。是因为在模板实例化时编译器拒绝任何隐式转
我遇到了以下代码(存储在 crtp.cc 中)的编译器相关问题: #include #include #include template class AlgebraicVectorExpres
在我的一个项目中,我使用与此处的答案 1 相同的 CRTP 方法(源自 enable_crtp):How do I pass template parameters to a CRTP? 但是我也需要
我目前正在使用 C++ 模板处理 CRTP 模式。在摆弄 visual studio 时,我发现了几种派生类可以调用函数的基类实现的方式/方法。下面是我正在使用的代码以及 3 行注释掉的代码,显示了如
我想创建一个模板类,为类提供通用方法,使其具有成员 m_Type,指定继承类提供的某种类型。考虑一下: template struct TypeAttribute { T m_Type; };
我是一名优秀的程序员,十分优秀!