Class 涉及 CRTP 和内部类型的专业化

Class specialization involving CRTP and inner type

我想构建以下 classes。 Baseclass是定义要实现的函数,Derived实现了这个接口。

template <class T, class V>
class IBase
{
public:
    virtual void foo(const typename V::t_args&) =0;
};

template<class T>
struct T_args
{
    T z;
};

class Derived : public IBase<double, Derived>
{
public:
    typedef T_args<double> t_args;

    Derived() {}

    void foo(const t_args& x)
    { /* do some stuff */ }
};

编译器抱怨 Derived 类型不完整;我不明白为什么。 有没有办法让这个 class 结构正确?

我被迫使用 c++98 进行编码,但我对 c++11 及更高版本的任何解决方案感兴趣。

在你的基本模板中 class:

virtual void foo(const typename V::t_args&) =0;

这是在引用其 V 模板参数的某些内部 class 或称为 t_args 的类型。引用 class 成员时,class 的定义必须完整(以便弄清楚 t_args 是什么)。您正在尝试按如下方式使用此模板 class:

class Derived : public IBase<double, Derived>

您正在为 V 传递 Derived,但它的 class 定义不完整。如果模板库class只引用了它的V参数,一般是"ok"。但是,您的模板要求其模板参数类型是完整的,因为它需要知道 t_args 到底是什么,而派生的 class 在完全定义之前是不完整的。但是在它的基 class 被完全定义之前它不能被完全定义。有点像先有鸡还是先有蛋的情况。

没有针对这种循环引用的交钥匙解决方案。唯一可以做的就是重组 class,所以你的 "argument" 类型是一个独立的 class,而不是派生的 class.

阅读 后,这里是我的问题的潜在解决方法,方法是在基础 class 的模板签名中添加 t_args class:

template <class V, class Args>
class IBase
{
public:
    typedef Args t_args;

    virtual void foo(const Args&) =0;
};

template<class T>
struct T_args
{
    T z;
};

template <class T>
class Derived : public IBase<Derived<T>, T_args<T> >
{
public:
    typedef typename Derived::IBase::t_args t_args;

    Derived() {}

    void foo(const t_args&)
    { /* do some stuff */ }
};

另一种解决方法是使用一些特征 class:

// The traits class
template <typename T> struct Arg;

template <class T, class V>
class IBase
{
public:
    virtual ~IBase() {}
    virtual void foo(const typename Arg<V>::t_args&) = 0; // V can be incomplete here
                                                          // but Arg<V> should be complete
};

// So go to define Arg<Derived>:
// Result class
template<class T>
struct T_args
{
    T z;
};

// Forward declaration, Arg<V> accept incomplete type
class Derived;

// Specialization for Derived
// should not use internal of Derived as it is incomplete
template <>
struct Arg<Derived>
{
    typedef T_args<double> t_args;
};

// Now definition of Derived
class Derived : public IBase<double, Derived>
{
public:
    typedef Arg<Derived>::t_args t_args; // Should probably go in IBase for ease usage

    Derived() {}

    void foo(const t_args& x) /* override */
    { /* do some stuff */ }
};

Demo