繁体   English   中英

如何用c++递归模板定义b+树状结构

[英]How to define a b+tree-like structure with c++ recursive templates

我正在创建一个类似 b+ 树的数据结构,不同之处在于每个节点级别能够保存不同类型的值(用于缓存目的)并且具有不同数量的子节点。

例如:

  • root-node 最多包含 8 个 level1-node 子节点和 Struct1 的值,
  • level1-node 最多包含 16 个 level2-node 子节点和 Struct2 的值,
  • level2-node 最多包含 32 个叶节点子节点和 Struct 3 的值,
  • 叶节点持有 StructLeaf 的值。

我不需要在运行时更改树结构,所以我想使用模板来配置它。 我期望上面示例的实例化看起来像这样:

Tree<StructLeaf, <8, Struct1>, <16, Struct2>, <32, Struct3>>()

和这样的模板定义,这不是实际的代码,只是我认为它可能看起来像这样:

// variadic template recursion 'entrypoint'
template<
    typename TLeafData, // do I have to set leaf data before variadic template, even if it is of different structure?
    <int TChildrenSize, typename TData>... TChildNodes> // list of pairs of nodes configurations, how to make it a variadic of pairs?
>
class Node;


// template recursion body
template<
    typename TLeafData, //same as before
    <int TChildrenSize, typename TData> TNode, // values for the current node, how to define a pair?
    <int TChildrenSize, typename TData>... TChildNodes> // same as before
>
class Node {
    TNode.TData data; // how to access TNode.TData?
    std::array<Node<TLeafData, TChildNodes...>, TNode.TChildrenSize> children; // how to pass TChildNodes and access TNode.TChildrenSize?
}


// template recursion end
template<
    typename TLeafData, //same as before
    <> // empty template to stop recursion, how to define it?
>
class Node {
    TLeafData data;
}

我看到如何在没有 TData 的情况下,仅使用 ChildrenSize,通过使用 int 的递归模板来制作这个结构,但我也想知道是否可以或如何将数据类型添加到模板?


我尝试为此使用模板的模板,但看起来它是用于传递对之外的另一个用例,因为我找不到访问内部模板值的方法。

template<template<int A, typename B> typename C>
class AClass {
    C.B data; // type B is unaccessable
}

描述这一点的自然递归方式是每个级别只知道下一个级别,例如:

using MyTree = Tree<Struct1, 8,
                    Tree<Struct2, 16,
                         Tree<Struct3, 32,
                              Leaf<StructLeaf>
                              >
                        >
                   >;

可能这应该区分内部节点类型和顶级树,但你明白了。


请注意,您的代码草图不是递归的,而是可变的。 您仍然可以对其进行递归,但这似乎比首先递归地定义它要多得多。

不完全是你问的,但是......一些建议......

  1. 如果只在ground case中需要strutLead ,就放在模板参数列表的最后一个position,不要放在第一个position
  2. 您可以将级别的维度和类型“包装”为其他类型的模板参数,比如TWrapper

所以你的tree变量变成

Node<TWrapper<8u, Struct1>, TWrapper<16u, Struct2>,
     TWrapper<32u, Struct3>, StructLeaf>  tree;

可以实现Node声明定义TWrapper

template <std::size_t, typename>
struct TWrapper
{ };

并声明Node如下

// template declaration
template <typename, typename...>
class Node;

作为接收强制类型名和类型名的可变序列

递归情况的声明可以简单地是Node的特化如下

// recursion case Node
template <std::size_t Dim, typename TData, typename ... Ts>
class Node<TWrapper<Dim, TData>, Ts...>
{
  TData  data;

  std::array<Node<Ts...>, Dim>  children;
};

从第一个TWrapper中获取数组的维度和TData类型,然后定义以下Node ,只需传递剩余的模板参数即可。

基本情况可以简单地写成Node的另一个特化如下

// groud case Node
template <typename TData>
class Node<TData>
{
  TData  data;
};

完整的编译示例如下

#include <array>

template <std::size_t, typename>
struct TWrapper
{ };

// template declaration
template <typename, typename...>
class Node;

// recursion case Node
template <std::size_t Dim, typename TData, typename ... Ts>
class Node<TWrapper<Dim, TData>, Ts...>
{
  TData  data;

  std::array<Node<Ts...>, Dim>  children;
};

// groud case Node
template <typename TData>
class Node<TData>
{
  TData  data;
};

struct Struct1 {};
struct Struct2 {};
struct Struct3 {};
struct StructLeaf {};

int main()
{
  Node<TWrapper<8u, Struct1>, TWrapper<16u, Struct2>,
       TWrapper<32u, Struct3>, StructLeaf>  tree;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM