确保类型名称类型是“派生的基”
Make sure that typename type is a Derived of Base
我有这种代码
template <typename D, typename T>
class tl1 {
std::list<T> mTs ;
public:
T & getTbyName() const ;
}
template <typename T, typename C>
class tl2 {
public:
std::string getName() { return mName ; }
private:
C & mC ;
std::string mName
}
class c2 ;
class cl1 : tl1<cl1, cl2> {
}
class cl2 : tl2<cl2, cl1> {
}
我如何检查(compile time
)T
是cl2
类型或derived from cl2
,C
是cl1
类型或derived from cl1
。我需要确定 cl2 类型,否则getTbyName
会一团糟。
谢谢你的时间
昆汀
您可以使用static_assert
和std::is_base_of
。
#include <type_traits>
struct B {};
template <typename T>
class C {
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
};
struct D : public B {};
struct KO {};
template class C<B>;
template class C<D>;
template class C<KO>;
int main()
{
}
main.cpp: In instantiation of 'class C<KO>':
main.cpp:16:16: required from here
main.cpp:7:5: error: static assertion failed: T should inherit from B
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
^
======= clang =======
main.cpp:7:5: error: static_assert failed "T should inherit from B"
static_assert(std::is_base_of<B, T>::value, "T should inherit from B");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:16:16: note: in instantiation of template class 'C<KO>' requested here
template class C<KO>;
^
在线演示
将 <type_traits>
中的std::is_base_of
与std::enable_if
结合使用:
template <typename T,
typename = typename std::enable_if<std::is_base_of<cl2, T>::value>::type>
class cl1 {
std::list<T> mTs ;
}
当你想要确定 A 是否是 B 的基数时,编译器需要知道类型定义或 A 和 B 必须相同(A 是 A 的基数)。
因此,您要检查一个模板参数是否派生自前向声明的类型。
从您后来的帖子来看,您还想检查您的 CRTP 基类是否实际用作其中一个参数的基类。
在后一种情况下,当 CRTP 基类专用化时,编译器没有所有信息,因为尚未定义派生类。
因此,您必须将评估推迟到稍后阶段,此时编译器具有必要的信息。为此,让我们创建一个帮助程序:
#include <utility>
class cl2;
class cl1;
template <typename Defer, typename Base, typename Derived>
struct deferred_is_base_of : std::is_base_of<Base, Derived>
{
};
理论上,这个类以后可以专门化,所以编译器不能假设defered_is_base_of
和std::is_base_of
相同。
假设我们需要一个构造函数(任何其他"必需"函数也可以):
template <typename Derived, typename Value>
class tl1
{
public:
template <typename Defer = void>
tl1()
{
static_assert(deferred_is_base_of<Defer, cl2, Value>::value,
"Value has to be derived from cl2");
static_assert(deferred_is_base_of<Defer, tl1, Derived>::value,
"Derived has to be derived from tl1");
}
};
构造函数是具有默认参数的模板。因此,您可以像往常一样调用它。但是编译器必须等待您执行此操作,因为您可能使用不同的模板参数。
这确实可以解决问题。编译器仅在调用构造函数时计算静态断言。到那时,将有足够的信息。
第二个模板的工作方式相同:
template <typename Derived, typename Value>
class tl2
{
public:
template <typename Defer = void>
tl2()
{
static_assert(deferred_is_base_of<Defer, cl1, Value>::value,
"Value has to be derived from cl1");
static_assert(deferred_is_base_of<Defer, tl2, Derived>::value,
"Derived has to be derived from tl2");
}
};
class cl1 : tl1<cl1, cl2>
{
cl1()
{
}
};
class cl2 : tl2<cl2, cl1>
{
cl2()
{
}
};
int main() {}
延迟模板评估是 TMP 工具箱中的强大工具。
编辑:正如@Brandon所指出的,这里不需要递延基数。将检查放入构造函数以延迟到此处就足够了。
相关文章:
- 存储模板类型以强制转换回派生<T>
- 在 C++ 中用派生类型重写成员函数
- 检查一个类型是否直接派生自"enable if"上下文中的另一个类型(是其子类型)
- 给定一个类型,如何派生一个泛型更广泛的类型(例如,用于溢出安全求和)?
- 在 C++ 中将对象转换为派生类型
- 如何检查派生类的类型?(C++实例)
- 创建派生自可变参数模板包的类型元组
- C++如果采用类类型的函数被传递派生类型,有没有办法给出错误?
- 返回派生类型时出现协变类型错误
- 静态自动 constexpr t = { "red" , "black" , "green" } 是什么类型;派生到?
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 在从仅移动类型派生的类中定义析构函数在使用 std::vector emplace_back或push_back创建时会
- (C++);动态决定函数的类型(派生类)
- 如何使variadic模板类方法以函数指针为参数,类型派生自函数模板
- 如何防止从 c++03 中的类型派生
- 如何为从特定类型派生的类型专门化模板
- 为什么在返回从函数的返回类型派生的类型本地对象时不选择 move 构造函数?
- 如何在模板类型中强制静态成员初始化?或如何获取从模板类型派生的所有类的计数
- 有没有任何方法可以从C++中的成员指针类型派生对象类型
- 在c++中基于另一个变量类型派生一个变量类型