我正在尝试在编译时为C ++提供一些依赖类型的数据结构。我有点解决了主要的例子,一个列表类型,其长度编码类型,又名。 list<T, length>
。有一些简单的不变量可以很容易地保存在这里,就像你可以确定附加两个列表将其长度的总和作为长度等。到目前为止琐碎。我现在正在转向依赖类型的树,也就是说。 binary_tree<T, height>
,以便我可以修改它以实现高度平衡的树。想法是丢弃任何会在编译时打破高度平衡的操作。对我来说,整个事情也是一种很好的递归思维练习。
我将展示我的尝试,稍后会询问错误。
// A binary tree of height N
template <typename T, std::size_t N>
struct binary_tree
{
constexpr binary_tree(const T &node, binary_tree<T, N-1> left,
binary_tree<T, N-1> right)
:root{node}, left{left}, right{right}, size{left.size + right.size + 1}
{}
const T root;
const binary_tree<T, N-1> left;
const binary_tree<T, N-1> right;
const std::size_t size; // num of elements in tree
constexpr static const std::size_t capacity = 2^N -1;
};
template <typename T>
struct binary_tree<T, 0>
{
const std::size_t size{0};
constexpr static const bool nil = true;
};
template <typename T>
using empty_tree = binary_tree<T,0>;
template <typename T, std::size_t N>
constexpr auto insert(const T& elem, const binary_tree<T, N> &tree) {
if constexpr (N == 0)
return binary_tree<T, 1>{elem, empty_tree<T>{}, empty_tree<T>{}};
else if (elem <= tree.root && tree.size < binary_tree<T, N>::capacity)
return binary_tree<T, N>{tree.root,
insert(elem, tree.left),
tree.right};
else if (elem <= tree.root && tree.size == binary_tree<T, N>::capacity)
return binary_tree<T, N + 1>{tree.root,
insert(elem, tree.left),
tree.right};
else if (elem > tree.root && tree.size < binary_tree<T, N>::capacity)
return binary_tree<T, N>{tree.root,
tree.left,
insert(elem, tree.right)};
else if (elem > tree.root && tree.size == binary_tree<T, N>::capacity)
return binary_tree<T, N + 1>{tree.root,
tree.left,
insert(elem, tree.right)};
}
int main() {
constexpr binary_tree<int, 1> tr1{2, empty_tree<int>{}, empty_tree<int> {}};
constexpr auto tr2 = insert(1, tr1);
}
问题是,我的insert
函数也试图实例化对其他分支的调用,因为只有第一个是constexpr if
。不知何故,我需要将所有情况都设为else if constexpr
,但这似乎不可能,因为比较elem
以查看要插入的子树不是constexpr
。为什么elem < tree.root
不是constexpr
,毕竟它们是两个常数值。
编辑:我意识到将左右子树带到相同高度是有问题的,对于一般树木不一定是这样。这让我更加困惑。