И всё бы хоршо, но! Для того, чтобы инстациировать класс tree_node мне нужен полностью определённый memory_manager, а ему в свою очередь нужен полностью определённый tree_node. Получается что-то такое
Здравствуйте, adontz, Вы писали:
A>Пишу дерево распределение памяти в котором должно регулироваться policy классом.
A>Сей класс имеет такой вид (все исходники сильно упрощены) A>
A>template <typename T>
A>class memory_manager
A> {
A> public:
A> static T * alloc();
A> static void free(T * pt);
A> }
A>
A>С другой стороны класс узла дерева имеет такой вид A>
A>template <typename M>
A>class tree_node
A> {
A> protected:
A> tree_node * left;
A> tree_node * right;
A> tree_node * parent;
A> public:
A> tree_node(
A> left_init = NULL,
A> right_init = NULL,
A> parent_init = NULL) :
A> left(left_init),
A> right(right_init),
A> parent(parent_init),
A> {
A> }
A> ~tree_node()
A> {
A> M::free(left);
A> M::free(right);
A> }
A> }
A>
A>И всё бы хоршо, но! Для того, чтобы инстациировать класс tree_node мне нужен полностью определённый memory_manager, а ему в свою очередь нужен полностью определённый tree_node. Получается что-то такое A>
A>tree_node<memory_manager<tree_node<memory_manager<tree_node<memory_manager<tree_node<memory_manager<.. :wow: ..> > > > > >
A>
A>Как бы это обойти? Что-то не варит у меня голова
Приходит на ум что-то вроде..
template <class T, template <class> class MemManager> class TreeNode
{
}
template <class T> class MemManager
{
}
TreeNode<MtType,ConcreteManager>...
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, g_i, Вы писали:
g_i>>Приходит на ум что-то вроде.. g_i>>
g_i>>template <class T, template <class> class MemManager> class TreeNode
g_i>>{
g_i>>}
g_i>>template <class T> class MemManager
g_i>>{
g_i>>}
g_i>>TreeNode<MtType,ConcreteManager>...
g_i>>
A>Я как-то не понял как этим пользоваться и почему у шаблона TreeNode появился второй параметр.
Это так называемый "шаблонный шаблонный параметр" (template template parameter).
При такой записи не нужно конкретизировать ConcreteManager типом, которым ты конкретизируешь TreeNode.
Т.е. фактически запись TreeNode< M , ConcreteManager > заменяет привычное TreeNode< M , ConcreteManager< M > > — позволяет не указывать дважды один и тот-же тип (тип M автоматически передается в качестве параметра для ConcreteManager. Ты ведь менеджер памяти типом M инициализировать должен — а не типом TreeNode<M>? Или нет?
Здравствуйте, adontz, Вы писали:
A>Пишу дерево распределение памяти в котором должно регулироваться policy классом.
A>Сей класс имеет такой вид (все исходники сильно упрощены) A>
A>template <typename T>
A>class memory_manager
A> {
A> public:
A> static T * alloc();
A> static void free(T * pt);
A> }
A>
A>С другой стороны класс узла дерева имеет такой вид A>
A>template <typename M>
A>class tree_node
A> {
A> protected:
A> tree_node * left;
A> tree_node * right;
A> tree_node * parent;
A> public:
A> tree_node(
A> left_init = NULL,
A> right_init = NULL,
A> parent_init = NULL) :
A> left(left_init),
A> right(right_init),
A> parent(parent_init),
A> {
A> }
A> ~tree_node()
A> {
A> M::free(left);
A> M::free(right);
A> }
A> }
A>
А где в этом коде собственно дерево? И почему узел самостоятельно распоряжается памятью и временем жизни других узлов?
Здравствуйте, g_i, Вы писали:
g_i>Это так называемый "шаблонный шаблонный параметр" (template template parameter). g_i>При такой записи не нужно конкретизировать ConcreteManager типом, которым ты конкретизируешь TreeNode. g_i>Т.е. фактически запись TreeNode< M , ConcreteManager > заменяет привычное TreeNode< M , ConcreteManager< M > > — позволяет не указывать дважды один и тот-же тип (тип M автоматически передается в качестве параметра для ConcreteManager. Ты ведь менеджер памяти типом M инициализировать должен — а не типом TreeNode<M>? Или нет?
Судя по примеру в начале топика таки нет.
то есть, имхо, должны быть как-то так:
Здравствуйте, folk, Вы писали:
F>А где в этом коде собственно дерево?
Дерево будет состоять из некоторого tree_node. Реально это будет что-то такое
template <typename memory_manager>
class tree
{
protected:
tree_node<memory_manager> root;
public:
//какие-то методы...
}
F>И почему узел самостоятельно распоряжается памятью и временем жизни других узлов?
Потому что в дереве иерархические отношения и листик без ветки смысла не имеет.
Поэтому если я удаляю некоторый узел, то все его подузлы тоже должны быть удалены.
Собственно дерево вполне себе работает и уже отлажено, просто возникла задача указывать способ распределение памяти.
В старую архитектуру дерева это вообще не укладывалось, приходиться всё перепроектировать
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, g_i, Вы писали:
g_i>>Ты ведь менеджер памяти типом M инициализировать должен — а не типом TreeNode<M>? Или нет?
A>Не, как раз типом TreeNode<M> A>Отсюда и рекурсия.
A>Я о чём-то таком подумал A>
A>template <typename T>
A>class MemManager
A> {
A> };
A>//
A>class TreeMemManager
A> {
A> public:
A> template <typename T>
A> class MMType : public MemManager<T>
A> {
A> };
A> };
A>//
A>template <typename M>
A>class TreeNode
A> {
A> public:
A> typedef typename M::MMType<TreeNode> mm_type;
A> };
A>TreeNode<TreeMemManager> tn;
A>
A>Но тогда рушится система автоматического выбора MemManager, вернее её придтся дублировать
A>Вот если бы можно было как-то так... A>
A>template <typename M>
A>class TreeNode
A> {
A> typedef M<TreeNode> mm_type;
A> }
A>
A>Но это уже мечты.
Я чую, тут где-то подстава. На уровне проектирования/дизайна Все это немножко не так делается..
Здраствуйте, adontz, Вы писали:
a> Пишу дерево распределение памяти в котором должно регулироваться policy a> классом.
хъ
a> Как бы это обойти? Что-то не варит у меня голова
А если попробовать ввести дополнительный уровень косвенности? Как, например, это сделано в std::list.