涉及CRTP和内部类型的类专门化

时间:2018-07-06 12:10:14

标签: c++ template-specialization crtp c++98

我想建立以下课程。基类定义要实现的功能,派生实现此接口。

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是不完整的类型。我不明白原因。 有什么办法使这个类结构正确吗?

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

3 个答案:

答案 0 :(得分:5)

在基本模板类中:

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

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

class Derived : public IBase<double, Derived>

您要为Derived传递V,但是其类定义不完整。如果模板基类仅引用了其V参数,则通常为“ ok”。但是,您的模板要求其模板参数类型完整,因为它需要知道t_args到底是什么,并且您的派生类在完全定义之前是不完整的。但是,直到完全定义其基类后,才能完全定义它。有点像鸡与蛋的情况。

对于这种类型的循环引用并没有交钥匙解决方案。唯一可以做的就是重组类,因此您的“参数”类型是一个独立的类,而不是派生类。

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

在阅读explanation by Sam Varshavchik之后,可以通过在基类的模板签名中添加StringSignature类来解决我的问题:

t_args