我编写了各种类型的二叉搜索树(经典,splay,reb-black,avl,Treap,随机等)。
对于每种类型的树,我定义了一个泛型类,它接收节点类型,键类型和键之间的函数比较作为参数。例如,对于p 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
使用&#34;正常&#34;节点和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>;
但是,当实例化以下函数时,最后一种方法会导致编译器错误(clang编译器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
不同。或者这是编译器的问题
答案 0 :(得分:3)
问题是类型现在看起来不同了。最初,你有:
template <typename Key, class Compare = less<Key>>
struct Avl_Tree : public Gen_Avl_Tree<AvlNode, Key, Compare>
所以Avl_Tree
是两种类型的模板:Key
和Compare
。现在,你有:
template <typename Key, class Compare = less<Key>>
using struct Avl_Tree = Gen_Avl_Tree<AvlNode, Key, Compare>;
此处,Avl_Tree
只是Gen_Avl_Tree
的别名,它是 3 类型的模板:NodeType
,Key
和{{ 1}}。好吧,Compare
不是一个类型,它是一个模板,但关键是它是3个事物的模板。
现在,你的功能:
NodeType
需要一个有两种类型的模板模板。这与别名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)
不匹配,因此编译错误完全正确。你可能想要做的是:
Avl_Tree
此版本的函数适用于派生的template <typename Tree>
tuple<Stat, Stat, int, int> sample_tree(Tree& tree,
gsl_rng * r, int n, int k)
{
// or equivalent...
using Key = typename Tree::Key;
using Compare = typename Tree::Compare;
// etc.
}
和别名Avl_Tree
。