推导和模板化使用之间有什么区别? (请参阅上下文)

时间:2014-12-31 17:24:59

标签: c++ inheritance c++11 using

我编写了各种类型的二叉搜索树(经典,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::NodeAvl_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不同。或者这是编译器的问题

1 个答案:

答案 0 :(得分:3)

问题是类型现在看起来不同了。最初,你有:

template <typename Key, class Compare = less<Key>>
struct Avl_Tree : public Gen_Avl_Tree<AvlNode, Key, Compare>

所以Avl_Tree是两种类型的模板:KeyCompare。现在,你有:

template <typename Key, class Compare = less<Key>>
using struct Avl_Tree = Gen_Avl_Tree<AvlNode, Key, Compare>;

此处,Avl_Tree只是Gen_Avl_Tree的别名,它是 3 类型的模板:NodeTypeKey和{{ 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