簡體   English   中英

有沒有辦法解決模板類中的前向聲明?

[英]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> {};

在編譯ParentProxy<Child, Parent>::Container的定義會在此行導致錯誤: static_cast<Proxy *>(ptrT)->m_ptrContainer = NULL; - 在匯編中, Child尚未定義,僅被聲明。 如果我將ParentChild的聲明順序更改為:

#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的成員?”。 原因如下:

  1. 當容器被銷毀時,它們的容器“擁有”的元素不會被自動刪除(是的,我知道boost::ptr_list )。
  2. 如果不添加其他類成員,則無法使用包含的元素引用容器。 例如,從Instance獲取Model
  3. 如果您確實添加了一個類成員來完成#2,那么當從容器中刪除元素時,您還需要更新它。
  4. 對於速度狂熱者 - 如果包含的元素不保持迭代器到它們在容器中的位置,則在刪除該元素之前必須首先搜索容器。

我不認為你向我們展示的代碼表明了你所問的問題。

我做了一些最小的修改以克服早期的編譯器錯誤,所以我可以達到可以重現你的問題的程度。 但是,這樣做,你的問題就不存在了。

以下是我的更改:

  • 添加#include <list>
  • typename Container::iterator替換iterator每個實例
  • 使Containerlist公開而不是私有地繼承,因此我可以訪問其iterator類型。

您可以嘗試逐個添加它們以查看每個解決的錯誤 - 它們都與您的問題無關。 或者您可以下載代碼並自行編譯。

我用三個不同的編譯器編譯了這個,clang-4.2,g ++ - 4.6和g ++ - 4.2-apple; 在適當的情況下,在C ++ 11和C ++ 98模式下; 啟用-Wall。 在所有情況下,它編譯時沒有任何錯誤或警告。

另外,我沒有看到引用的行如何產生您描述的錯誤。 TC是否不完整無關緊要,因為您所做的只是:

  • static_cast一個T *到一個Proxy * ,只需要聲明T ,沒有定義。
  • 訪問Proxy的成員,該Proxy不依賴於類型T
  • C *設置為NULL,只需要聲明C ,而不是定義。

一行依賴於在iterator上調用operator * ,而且顯然是你的自定義類可能以某種方式依賴於TC ,但這不可能在下一行引起錯誤。

所以,有一些可能性:

  • 錯誤不是您描述的錯誤,也不是您描述的錯誤,問題出在iterator類或您未向我們展示的list類中。
  • 您向我們展示的代碼與您的真實代碼有很大的不同,它甚至不再有導致問題的部分痕跡。
  • 我的瑣碎變化並不像我想象的那樣微不足道,並以某種方式解決了你的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM