如何在CRTP中实现向下转换是否有效的编译时检查
How to implement a compile-time check that a downcast is valid in a CRTP?
我有一个普通的旧CRPT(请不要被访问限制分散注意力-问题不在于它们):
template<class Derived>
class Base {
void MethodToOverride()
{
// generic stuff here
}
void ProblematicMethod()
{
static_cast<Derived*>(this)->MethodToOverride();
}
};
通常是这样使用的:
class ConcreteDerived : public Base<ConcreteDerived> {
void MethodToOverride()
{
//custom stuff here, then maybe
Base::MethodToOverride();
}
};
现在static_cast
困扰着我。我需要向下强制转换(而不是向上强制转换),所以我必须使用显式强制转换。在所有合理的情况下,强制转换都是有效的,因为当前对象确实属于派生类。
但是,如果我以某种方式改变了层次结构,强制转换现在变得无效怎么办?
在这种情况下,我是否可以强制执行一个编译时检查,以确保显式向下转换是有效的?
在编译时你只能检查静态类型,这就是static_cast
已经做的。
给定一个Base*
,它只能并且只能在运行时知道它的动态类型是什么,也就是说,它是否实际上指向ConcreteDerived
或其他东西。所以如果你想检查这个,它必须在运行时完成(例如通过使用dynamic_cast
)
为了更安全,您可以向Base添加一个受保护的构造函数,以确保某些是从它派生的。那么唯一的问题就是对于那些真正愚蠢的人:
class ConcreteDerived : public Base<SomeOtherClass>
但是这应该在第一次代码审查或测试用例中被捕获。
要扩展@Bo Persson所说的内容,您可以在所述构造函数中执行编译时检查,例如使用Boost。TypeTraits or c++ 0x/11 <type_traits>
:
#include <type_traits>
template<class Derived>
struct Base{
typedef Base<Derived> MyType;
Base(){
typedef char ERROR_You_screwed_up[ std::is_base_of<MyType,Derived>::value ? 1 : -1 ];
}
};
class ConcreteDerived : public Base<int>{
};
int main(){
ConcreteDerived cd;
}
似乎存在一种在编译时检查CRPT正确性的方法。
通过使Base抽象(向Base添加一些纯虚方法),我们保证任何Base实例都是某个派生实例的一部分。
通过将所有Base构造函数设置为私有,可以防止Base的不良继承。
通过声明Derived为Base的友类,我们允许CRPT所期望的唯一继承。
在此之后,CRPT向下转换应该是正确的(因为某些东西是从基类继承的,并且这个"某些东西"可能只是派生的,而不是其他类)
也许出于实际目的,第一步(使Base抽象)是多余的,因为成功的static_cast保证Derived在Base层次结构中的某个位置。如果Derived继承了Base <Derived>
(正如CRPT所期望的那样),但同时Derived在派生代码的某个地方创建了Base <derived>
的另一个实例(没有继承)(它可以,因为它是友元),则只允许出现外来错误。然而,我怀疑是否有人会不小心写出如此奇特的代码。
当你做如下操作时:
struct ConcreteDerived : public Base<Other> // Other was not inteded
可以创建class
的对象(派生或基类)。但是如果您尝试调用该函数,它只会给出与static_cast
相关的编译错误。我认为它将满足所有实际情况。
- 如果变量名称不跟在 char* 后面,const char* 是否有效?
- 钳制迭代器是否有效
- 检查由括号、方括号和大括号组成的一组方括号是否有效?
- 在函数内创建的对象的范围 - 如果在函数外部存储和访问引用,它们是否有效?
- 模板签名解析为 void(void) 被 GCC 拒绝;这是否有效C++?
- 我如何知道作为参数的size_t在函数中是否有效?
- 是否可以在C++中获取 CHAR 的有效十六进制地址?
- 我的运算符重载是否有效<<(流插入)左操作数不是 ostream
- C++ 返回指向函数内定义的静态数组的指针是否有效?
- 模板变量是否允许在多个翻译单元中并有效合并?
- 错误:在尝试检测 std::cout 是否<< t 时,功能强制转换为数组类型;有效
- 声明后,gcc 的动态大小数组是否与标准数组有效相同?
- 此递归模板类型定义是否有效C++?
- 将 C 函数转换为 C++ 以检查数字是否有效
- 函数参数的名称与调用函数时使用的变量相同是否有效?
- 如何检查输入是否有效?
- 如何检查用户的输入是否有效以及我正在寻找的数字?
- 堆分配对于大型块中的分页是否更有效?
- 在函数中按值传递 unordered_map/unordered_set 是否有效? C++
- 如何检查isupper(cstr)是否有效?