И всё бы хоршо, но! Для того, чтобы инстациировать класс 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.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, adontz, Вы писали:
A>Беру решение g_i A>Всем спасибо. A>rebind тоже рабочее решение, но выглядит страшно
Здравствуйте, g_i, Вы писали:
A>>Пишу дерево распределение памяти в котором должно регулироваться policy классом. g_i>А можно полюбопытствовать, почему менеджеру памяти нужен все же именно узел — почему входящим типом не обойтись не обойтись?
Ну узлы-то разные бывают. Ведь надо выделять память не только под 3 указателя, но и под дополнительные данные. А они кстати тоже разные. Если их ещё как-то можно охаректеризовать парой {data, key} то ничего конкретного об этих data и key сказать уже нельзя.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, g_i, Вы писали:
A>>>Пишу дерево распределение памяти в котором должно регулироваться policy классом. g_i>>А можно полюбопытствовать, почему менеджеру памяти нужен все же именно узел — почему входящим типом не обойтись не обойтись?
A>Ну узлы-то разные бывают. Ведь надо выделять память не только под 3 указателя, но и под дополнительные данные. А они кстати тоже разные. Если их ещё как-то можно охаректеризовать парой {data, key} то ничего конкретного об этих data и key сказать уже нельзя.
Вот тут немножко непонятно, как менеджер разберется, что с этими данными делать (ввиду того, что "ничего конкретного об этих data и key сказать уже нельзя"). Чтобы принять решение об определенных действиях над данными объекта Node (учитывая конструктивные особенности этого объекта), он должен, наверное, иметь специализацию для конкретного класса Node — полученной на лету реализацией шаблонного класса, вроде, не обойтись?
Здравствуйте, g_i, Вы писали:
g_i>Вот тут немножко непонятно, как менеджер разберется, что с этими данными делать (ввиду того, что "ничего конкретного об этих data и key сказать уже нельзя"). Чтобы принять решение об определенных действиях над данными объекта Node (учитывая конструктивные особенности этого объекта), он должен, наверное, иметь специализацию для конкретного класса Node — полученной на лету реализацией шаблонного класса, вроде, не обойтись?
А менеджер делать ничего и не должен, он должен только выделять и освобождать память под эти данные. Причём есть две операции выделения: под новый элемент и под копию уже существующего элемента.
Здравствуйте, adontz, Вы писали:
A>Здравствуйте, g_i, Вы писали:
g_i>>Вот тут немножко непонятно, как менеджер разберется, что с этими данными делать (ввиду того, что "ничего конкретного об этих data и key сказать уже нельзя"). Чтобы принять решение об определенных действиях над данными объекта Node (учитывая конструктивные особенности этого объекта), он должен, наверное, иметь специализацию для конкретного класса Node — полученной на лету реализацией шаблонного класса, вроде, не обойтись?
A>А менеджер делать ничего и не должен, он должен только выделять и освобождать память под эти данные. Причём есть две операции выделения: под новый элемент и под копию уже существующего элемента.
Вообще, вопрос интересный, и дискуссию можно было бы продолжить. Но тема начинает потихоньку расползаться, а еще и работать надо.. В общем, удачи.
Здравствуйте, g_i, Вы писали:
g_i>Вообще, вопрос интересный, и дискуссию можно было бы продолжить. Но тема начинает потихоньку расползаться, а еще и работать надо.. В общем, удачи.
У нас ещё будет такая возможность Некоторая часть кода скорее всего будет выставлена в форуме Исходники