[英]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.