2015-11-12 148 views
5

我嘗試編寫自定義STL樣式的容器。爲了簡單起見,我們假設它是一個列表。我擡起頭,標準的方式來定義這樣的容器:作爲模板參數的嵌套類

template <typename T, typename A = std::allocator<T> > class mylist; 

現在,我想用一個嵌套類來管理列表的節點:

(inside mylist) 
class node { 
    T data; 
    node *next; 
} 

這是我的理解是,我不需要在node的定義前加上template說明符,因爲編譯器將爲mylist的模板參數的每個組合實例化單獨的類mylist<T,A>::node

但是,現在我不僅需要爲T類型的數據本身分配內存,還要爲它們的包裝node分配內存。因此,我希望默認模板參數的類型爲std::allocator<mylist<T>::node>。在這一點上,雖然,mylist尚未宣佈,編譯器是可以理解打亂:

error: `mylist' was not declared in this scope 

一個將如何解決這個難題?有兩個約束:

  • 通常,我會宣佈缺少的類沒有完全聲明其內容。但是,由於它嵌套在我想要聲明的事物中,所以這不是一個選項。
  • 我需要node嵌套,因爲它需要訪問分配器實例mylist。例如,我在node上宣佈operator=遞歸地發生大量內存管理。這對於一個列表來說可能是過分的,你可以在mylist之內做到這一點,從而降低nodeA的參數依賴性,但是對於我正在實現的數據結構來說,這是至關重要的。
+1

可能值得看看g ++如何實現'std :: list'。 –

+0

看看分配器'rebind' – Yakk

回答

2

默認分配器的類型參數是什麼並不重要,只是實際的類型。您可以使用rebind_allocstd::allocator_traits

Alloc::rebind<T>::other如果存在的話,否則Alloc<T, Args>如果這AllocAlloc<U, Args>

得到你需要的東西:

template <typename T, typename A = std::allocator<T> > 
class mylist { 
    class node { ... }; 

    using NodeAlloc = typename std::allocator_traits<A>::template rebind_alloc<node>; 
}; 

然後用NodeAlloc讓你node s。這樣,如果用戶沒有指定分配器,則會得到默認的std::allocator<T>,然後使用std::allocator<node>。這正是你想要的,而不必暴露node

+0

這不就是標準庫的工作原理嗎? – Walter

0

我需要節點被嵌套,因爲它需要訪問的mylist

分配器實例別那麼肯定。他們可以是朋友:

template <typename, class> class list; 

template <typename T> 
struct node { 
    // ... 
}; 

template <typename T, class Alloc=std::allocator<T> > 
class list { 
    friend node<T>; 
    // ... 
}; 

如果你不想node是你的文件的訪問之外,只是忽略它在你的頭文件(.h/.hpp)。

+0

我總是忘記朋友......我決定用'rebind_alloc'解決方案,因爲它似乎適合我的具體問題。 – Jonas