2015-11-12 2 views
5

Я пытаюсь написать пользовательский контейнер в стиле STL. Для простоты предположим, что это список. Я посмотрел стандартный способ определения такого контейнера:Вложенный класс как параметр шаблона

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

Теперь я хочу, чтобы управлять узлами списка, используя вложенный класс:

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

Это мое понимание того, что я не нужен поместите спецификатор template перед определением node, поскольку компилятор будет создавать отдельные классы mylist<T,A>::node для каждой комбинации параметров шаблона mylist.

Однако теперь мне нужно выделить память не только для данных типа T, но и для их обертки node. Таким образом, я хотел бы, чтобы параметр шаблона по умолчанию имел тип std::allocator<mylist<T>::node>. В этот момент, однако, mylist еще не была объявлена, и компилятор, по понятным причинам расстроило:

error: `mylist' was not declared in this scope 

Как бы один решить эту головоломку? Существует два ограничения:

  • Обычно я объявляю пропавший класс без полного объявления его содержимого. Однако, поскольку он вложен внутри самой вещи, которую я хочу объявить, это не вариант.
  • Мне нужно node быть вложенным, так как ему нужно получить доступ к экземпляру распределителя mylist. Например, у меня есть operator=, объявленный на node, где много управления памятью происходит рекурсивно. Это может быть излишним для списка, и вы можете сделать это в пределах mylist, тем самым снижая параметрическую зависимость node от A, но это имеет решающее значение для структуры данных, которую я реализую.
+1

Возможно, стоит посмотреть, как g ++ реализует 'std :: list'. –

+0

Посмотрите на распределитель 'rebind' – Yakk

ответ

2

Не имеет значения, что такое аргумент типа распределителя по умолчанию, только фактический тип. Вы можете использовать rebind_alloc из std::allocator_traits:

Alloc::rebind<T>::other, если присутствует, в противном случае Alloc<T, Args> если Alloc является Alloc<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

Смежные вопросы