如何在编译时检测基类的模板参数(对于错误)?

时间:2012-01-08 15:32:54

标签: c++ templates inheritance derived-class

我一直在使用Curiously recurring template pattern。一般代码如下所示:

template <typename T> void genericFunction(T &);
template <typename T> struct Functionality {
    void genericMethod() {
        genericFunction(*((T *)this)) ;
    }
};

struct Klass : public Functionality<Klass> {};

void main() {
    Klass obj ;
    obj.genericMethod();
}

template <> void genericFunction<Klass>(Klass &obj) {
    //do stuff with Klass &obj here
}

我今天遇到了一个错误,这花了我大约90分钟的拔毛,这个错误是由于我的基类继承声明使用了一个不正确的模板参数引起的,有点像这样:

struct Klass : public Functionality<SomeOtherKlass> {}; //SomeOtherKlass wrong!!!

我想增强我的代码,以便检测派生类和基类模板参数之间的不匹配(运行时,编译时间,随时:)),这是否可能?,谢谢。

5 个答案:

答案 0 :(得分:3)

您可以断言关系,例如genericMethod()使用Boost或C ++ 11功能:

BOOST_STATIC_ASSERT(( boost::is_base_of<Functionality<T>, T>::value ));

...虽然假设其他类也不是来自Functionality<T>

另一种方法是在测试版本中在运行时声明关系:

template <typename T> struct Functionality {
#ifdef TEST_BUILD
    virtual ~Functionality() {}
#endif
    void genericMethod() {
#ifdef TEST_BUILD
        assert(dynamic_cast<T*>(this));
#endif
        genericFunction(*((T *)this)) ;
    }
};

请注意,该测试不适用于constructors and destructors

答案 1 :(得分:2)

在C ++ 11中,以下内容应该有效:

template<typename T> class Base
{
  friend T; // allowed in C++11
private:
  ~Base() {}
public:
  // ...
};

class Derived: public Base<Derived> {}; // OK

class WronglyDerived: public Base<Derived> {}; // Error: destructor of base class is private

答案 2 :(得分:1)

您可以使用dynamic_cast,如果您的参数类型错误,则返回null。 (你需要在基础中至少有一个虚函数才能工作 - 比如析构函数。)

如果你担心效率,boost会有一个polymorphic_cast,它在调试模式下进行动态转换,但是用于生产的静态转换。

(无论如何,避免使用C风格的演员会很好。)

答案 3 :(得分:0)

假设您将模板化构造函数添加到基础,该构造函数将指针指向任意类型;

template<class U> Functionality(U *) { ... }

然后每个派生类的构造函数都可以将它的this指针传递给构造函数,并且在构造函数的主体中,你只是静态断言U和T是相同的类型。

构造函数参数从未实际使用过,因此应完全优化。如果这是唯一的基类构造函数,你不能忘记调用它。唯一的问题是如果你传递的不是这个。

答案 4 :(得分:-1)

到目前为止,最明显的建议是使用dynamic_cast在Base类构造函数中公开格式错误的继承声明,如下所示:

#include <iostream>
template <typename T> struct Base {
    Base() {
        std::cout<<dynamic_cast<T *> (this)<<std::endl;
    }
    virtual void iampolymorphic(){}
};
struct Decoy {} ;
struct Pass : public Base<Pass>{}; //correct
struct Fail : public Base<Decoy>{}; //incorrect
int main() {
    Pass p ;
    Fail f ;
    return 1 ;
}

此代码编译于g ++ 4.6.1,Amd64 Xubuntu 11.10。两个动态强制转换操作的输出都是空指针。欢迎评论,批评和观察。