Я программирую различные типы двоичных деревьев поиска (классический, splay, reb-black, avl, Treap, рандомизированный и т. д.).Какая разница между деривацией и шаблонами с использованием? (см. контекст)
Для каждого типа дерева я определяю общий класс, который получает в качестве параметров тип узла, тип ключа и сравнение функций между ключами. Например, для р AVL дерева определяют (и реализации) следующий класс:
template <template <typename> class NodeType, typename Key, class Compare>
class Gen_Avl_Tree
{
...
};
Одной из причин такого подхода заключается в том, чтобы отделить обработку памяти обработки дерева. Дерево не заботится о распределении или освобождении узла, просто вставляет, удаляет или ищет узлы с ключевым значением; и т. д. с другими операциями. Другая причина заключается в том, чтобы позволить возможность в соответствии с условиями приложения, чтобы узел имел или не являлся виртуальным деструктором.
Затем я определяю два класса следующим образом:
template <typename Key, class Compare = less<Key>>
struct Avl_Tree : public Gen_Avl_Tree<AvlNode, Key, Compare>
{
using Base = Gen_Avl_Tree<AvlNode, Key, Compare>;
using Base::Base;
};
template <typename Key, class Compare = less<Key>>
struct Avl_Tree_Vtl : public Gen_Avl_Tree<AvlNodeVtl, Key, Compare>
{
using Base = Gen_Avl_Tree<AvlNodeVtl, Key, Compare>;
using Base::Base;
};
Avl_Tree
использует «нормальные» узлы и Avl_Tree_Vtl
использует узлы с виртуальным деструктором. Оба типа экспортируют вложенный тип Node
. В случаях: Avl_Tree::Node
и Avl_Tree_Vtl::Node
.
Оценив тот факт, что оба класса функционально идентичен, я счел более целесообразным заменить предыдущие определения для следующих целей:
template <typename Key, class Compare = less<Key>>
using struct Avl_Tree = Gen_Avl_Tree<AvlNode, Key, Compare>;
template <typename Key, class Compare = less<Key>>
using Avl_Tree_Vtl = Gen_Avl_Tree<AvlNodeVtl, Key, Compare>;
Однако этот последний подход приводит к ошибке компилятора (лязг компилятор 3,6), когда следующая функция экземпляра:
template <template <typename, class> class TreeType,
typename Key,
class Compare = Aleph::less<Key>>
tuple<Stat, Stat, int, int> sample_tree(TreeType<Key, Compare> & tree,
gsl_rng * r, int n, int k)
{ ... }
из другой функции:
template < template <typename /* key */, class /* Compare */> class TreeType>
void test(unsigned long n, gsl_rng * r)
{
...
tuple<Stat, Stat, int, int> stats = sample_tree(tree, r, i, log(i)/log(2));
...
}
линия как:
test<Avl_Tree>(n, r);
вызывает ошибку:
timeAllTree.C:190:6: error: no matching function for call to 'sample_tree'
sample_tree(tree, r, i, log(i)/log(2));
^~~~~~~~~~~
timeAllTree.C:344:4: note: in instantiation of function template specialization
'test<Avl_Tree>' requested here
test<Avl_Tree>(n, r);
^
timeAllTree.C:56:29: note: candidate template ignored: could not match 'type-parameter-0-1'
against 'AvlNode'
tuple<Stat, Stat, int, int> sample_tree(TreeType<Key, Compare> & tree,
^
В противоположность этому, Avl_Tree
определяется выводом из Gen_Avl_Tree
компилируется и работает отлично.
Мой вопрос в том, есть ли основания полагать, что Avl_Tree
от Gen_Avl_Tree
функционально отличен от Avl_Tree
. Или это проблема с компилятором
Шаблон псевдонима никогда не выводится при выводе аргумента шаблона, поэтому вы должны явно передать его 'sample_tree'. Есть ли причина, по которой вы не можете заставить 'sample_tree' просто взять аргумент типа« Дерево »? –
Я не смог воспроизвести проблему. Я попытался сделать минимальный пример, но он компилируется в порядке: http://ideone.com/W0eRXJ –
@VaughnCato Это странно. Я могу воспроизвести с гораздо более простым примером, который не работает как на gcc, так и на clang, но работает на ideone ... – Barry