如何实现编译时检查转发在CRTP中是否有效?

时间:2011-05-06 06:41:44

标签: c++ casting crtp static-cast upcasting

我有一个普通的旧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困扰我了。我需要一个向下投射(不是向上投射),所以我必须使用一个明确的演员。在所有合理的情况下,强制转换都是有效的,因为当前对象确实是派生类。

但是如果我以某种方式改变了层次结构并且演员现在变得无效呢?

我可以以某种方式强制执行编译时检查,在这种情况下显式向下转发有效吗?

5 个答案:

答案 0 :(得分:5)

在编译时你只能检查静态类型,这就是static_cast已经做过的事情。

给定Base*,它只是,并且只能在运行时知道它的动态类型是什么,也就是说它是否实际指向{{1} }} 或者是其他东西。因此,如果要检查此项,则必须在运行时完成(例如,使用ConcreteDerived

答案 1 :(得分:4)

为了更加安全,您可以向Base添加受保护的构造函数,以确保某些是从它派生的。那么唯一的问题就是真正的愚蠢:

class ConcreteDerived : public Base<SomeOtherClass>

但是应该通过第一次代码审查或测试用例来捕获。

答案 2 :(得分:3)

要扩展@Bo Persson所说的内容,你可以使用例如Boost.TypeTraits或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;
}

完整示例on Ideone

答案 3 :(得分:2)

似乎存在一种在编译时检查CRPT正确性的方法。

通过使Base抽象(向Base添加一些纯虚方法),我们保证任何Base实例都是某个派生实例的一部分。

通过将所有Base构造函数设为私有,我们可以防止Base的不良继承。

通过声明Derived为Base的朋友,我们允许CRPT预期的唯一继承。

在此之后,CRPT downcast应该是正确的(因为某些东西是从base继承而且这个“某些东西”可能只是Derived,而不是其他类)

也许出于实际目的,第一步(制作Base摘要)是多余的,因为成功的static_cast保证Derived位于Base层次结构中的某个位置。如果Derived与Base <Derived> 一起(如CRPT所期望的那样),这只允许奇怪的错误,但同时Derived在派生代码中的某处创建了Base <derived> (没有继承)的另一个实例(它可以,因为它是朋友)。但是,我怀疑有人可能会不小心写出这种异国情调的代码。

答案 4 :(得分:1)

当您执行以下操作时:

struct ConcreteDerived : public Base<Other>  // Other was not inteded

您可以创建class(派生或基础)的对象。但是如果你尝试调用该函数,它只会提供与static_cast相关的编译错误。恕我直言,它将满足所有实际情况。

如果我正确地理解了这个问题,那么我觉得答案就在你的问题中。 :)