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 */ }
};
我想构建以下 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.
阅读 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 */ }
};