[英]Any way to resolve forward declaration in a template class?
我有一个模板类定义如下:
template <typename T> void ProxyNoOp(T *) {}
template <typename T> void ProxyDelete(T * ptrT) {delete ptrT;}
template <typename T, typename C, void (* Release)(T *) = ProxyNoOp<T> >
class Proxy
{
public:
class Container : public std::list<T *>
{
public:
Container() {}
~Container() {clear();}
void clear()
{
iterator clsEnd = end();
for (iterator clsCurrent = begin(); clsCurrent != clsEnd; ++clsCurrent)
{
T * ptrT = *clsCurrent;
static_cast<Proxy *>(ptrT)->m_ptrContainer = NULL;
Release(ptrT);
}
}
};
private:
iterator m_clsPosition;
C * m_ptrContainer;
public:
Proxy() : m_ptrContainer(NULL) {}
~Proxy()
{
if ( m_ptrContainer != NULL )
{
Container * ptrContainer = static_cast<Container *>(m_ptrContainer);
static_cast<std::list<T *> >(ptrContainer)->erase(m_clsPosition);
}
}
C * GetContainer() const {return m_ptrContainer;}
};
为简洁起见,已删除或更改了许多代码。 数据结构的概念是,容器不仅维护对包含元素的引用,而且包含的元素保持对容器的引用PLUS它们在容器中的位置,使得快速删除(恒定时间)和自动(在析构函数中调用) )
此代码可以证明此方法存在问题:
#include "proxy.h" // the above template class
class Child;
class Parent : public Proxy<Child, Parent>::Container {};
class Child : public Proxy<Child, Parent> {};
在编译Parent
, Proxy<Child, Parent>::Container
的定义会在此行导致错误: static_cast<Proxy *>(ptrT)->m_ptrContainer = NULL;
- 在汇编中, Child
尚未定义,仅被声明。 如果我将Parent
和Child
的声明顺序更改为:
#include "proxy.h"
class Parent;
class Child : public Proxy<Child, Parent> {};
class Parent : public Proxy<Child, Parent>::Container {};
Proxy<Child, Parent>
的定义导致此行出错: Container * ptrContainer = static_cast<Container *>(m_ptrContainer);
,原因与之前相同 - 在编译中的那一点, Parent
没有完全定义。
有什么方法可以解决这个问题,仍然使用模板吗? STL,BOOST等中是否有标准数据结构来实现这一目标?
编辑:
代码将不会按原样编译,我应该更清楚(从上面引用自己: 为了简洁起见,已经删除或更改了许多代码。 )。 它实际上并没有使用std::list<T *>
,而是一个实际上相同的自定义双向链接。 当我只询问这个问题时,我不想发布大量的辅助代码。
我并没有要求对数据结构本身进行批评(尽管我听得很清楚),但对于那些想知道为什么在这里创建的人来说,有几个例子:
游戏引擎具有这些模型的模型和实例,例如战争游戏,其中有一个坦克模型和由其创建的任意数量的坦克。 这些类可以这样编写:
class Instance;
class Model : public Proxy<Model, Instance, ProxyDelete<Instance> >::Container {...};
class Instance : public Proxy<Model, Instance, ProxyDelete<Instance> > {...};
删除模型时,也应删除从该模型创建的所有实例(因此, ProxyDelete<Instance>
模板参数),因为没有模型的实例存在实例是没有意义的。
假设您的图形用户界面(GUI)渲染器跟踪所有可见元素(按钮,框架等),因此它知道要渲染的内容,但文本的呈现方式不同,因为它是对图形API的不同调用:
class GuiTextElement;
class GuiRenderer : public Proxy<GuiRenderer, GuiTextElement, ProxyNoOp<GuiTextElement> >::Container {...};
class GuiTextElement : public Proxy<GuiRenderer, GuiTextElement, ProxyNoOp<GuiTextElement> > {...};
精明的人会说“为什么不简单地将std::list<Instance *>
为Model
的成员,将std::list<GuiTextElement *>
为GuiRenderer
的成员?”。 原因如下:
boost::ptr_list
)。 Instance
获取Model
。 我不认为你向我们展示的代码表明了你所问的问题。
我做了一些最小的修改以克服早期的编译器错误,所以我可以达到可以重现你的问题的程度。 但是,这样做,你的问题就不存在了。
以下是我的更改:
#include <list>
。 typename Container::iterator
替换iterator
每个实例 Container
从list
公开而不是私有地继承,因此我可以访问其iterator
类型。 您可以尝试逐个添加它们以查看每个解决的错误 - 它们都与您的问题无关。 或者您可以下载代码并自行编译。
我用三个不同的编译器编译了这个,clang-4.2,g ++ - 4.6和g ++ - 4.2-apple; 在适当的情况下,在C ++ 11和C ++ 98模式下; 启用-Wall。 在所有情况下,它编译时没有任何错误或警告。
另外,我没有看到引用的行如何产生您描述的错误。 T
或C
是否不完整无关紧要,因为您所做的只是:
static_cast
一个T *
到一个Proxy *
,只需要声明T
,没有定义。 Proxy
的成员,该Proxy
不依赖于类型T
C *
设置为NULL,只需要声明C
,而不是定义。 前一行依赖于在iterator
上调用operator *
,而且显然是你的自定义类可能以某种方式依赖于T
或C
,但这不可能在下一行引起错误。
所以,有一些可能性:
iterator
类或您未向我们展示的list
类中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.