使用CRTP时,在基类中使用非模板派生类的typedef

Using typedefs of a non-template derived class in the base class when using CRTP

本文关键字:派生 typedef CRTP 基类 使用      更新时间:2023-10-16

我使用CRT模式,希望基类从派生类中看到typedef。在这篇文章中,@James McNellis建议使用base_traits类来实现这一点,并且效果很好。但在那篇文章中描述的情况下,派生类本身就是一个模板。当派生类不是模板时,此方法在VS2010中不起作用。

template <class D>
struct base_traits;
template <class D>
struct base
{
    typedef typename base_traits<D>::value_t value_t;
};
struct derived : base<derived>
{
    typedef typename base_traits<derived>::value_t value_t;
};
template<>
struct base_traits<derived>
{
    typedef int value_t;
};

上面的代码给出了很多错误。第一个是:

错误C2027:使用未定义的类型"base_traits "

在CCD_ 3类的typedef的行上。

base_traits<derived>必须在使用前声明和定义,因为它是base<derived>的隐式安装所必需的(下面,我转发声明的derived):

template <class D>
struct base_traits;

template <class D>
struct base
{
    typedef typename base_traits<D>::value_t value_t;
};
struct derived;
template<>
struct base_traits<derived>
{
    typedef int value_t;
};
struct derived : base<derived>
{
    typedef base_traits<derived>::value_t value_t;
};

int main(void)
{
    derived d;
}

实时演示

§14.7.3[温度解释规范]/p7:

函数显式专用化声明的位置模板、类模板、变量模板、的成员函数类模板,类模板的静态数据成员,成员类模板的类、类模板的成员枚举,类模板的成员类模板,成员函数模板类模板的静态数据成员模板,类模板的成员模板的成员函数,成员非模板类的成员模板的函数,静态数据非模板类的成员模板,的成员函数模板类模板的成员类等,以及局部类模板、变量模板的专门化声明,非模板类的成员类模板,静态数据成员非模板类的模板,类的成员类模板模板等会影响程序是否根据显性专业化的相对定位声明及其在翻译单元中的实例化点如上文和下文所述撰写专业文章时小心它的位置;或者将其编译将是一种尝试以点燃它的自焚

特别是(§14.7.3[温度解释规范]/p6),

如果一个模板[…]是显式专门化的,那么该专门化应在首次使用该专业之前声明会导致在每个发生这种使用的翻译单位;没有诊断必需。如果程序没有为显式专门化和[…]专门化在某种程度上被使用这将导致发生隐式实例化[…],程序格式不正确,不需要诊断。

显式专门化base_traits<derived>必须在定义derived之前声明和定义,否则从base<derived>继承和使用base_traits<derived>::value_t都会触发隐式实例化。因此:

template <class D>
struct base_traits;
template <class D>
struct base
{
    typedef typename base_traits<D>::value_t value_t;
};
struct derived;
template<>
struct base_traits<derived>
{
    typedef int value_t;
};
struct derived : base<derived>
{
    typedef base_traits<derived>::value_t value_t;
};