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

How to detect template parameters of base classes at compile time (for errors)?

本文关键字:参数 错误 编译 基类 检测      更新时间:2023-10-16

我一直在使用奇怪的重复模板模式。一般代码如下:

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!!!

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

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

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

尽管这是假设另一个类也不是从CCD_ 2派生的。

另一种选择是在测试构建的运行时断言关系:

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)) ;
    }
};

请注意,该测试不会在构造函数和析构函数

中工作

在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

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

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

(无论如何,最好避免使用C样式的强制转换。)

假设您向基添加了一个模板化构造函数,该构造函数接受指向任意类型的指针;

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

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

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

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

#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上编译。两个动态强制转换操作的输出都是空指针。欢迎提出评论、批评和意见。