模板类的树,其中 chilldren 是 std::array of std::unique_ptr
Posted
技术标签:
【中文标题】模板类的树,其中 chilldren 是 std::array of std::unique_ptr【英文标题】:Tree of template class where chilldren are std::array of std::unique_ptr 【发布时间】:2015-04-02 13:09:59 【问题描述】:我的情况如下:
template<size_t Level>
class Node
public:
Node()
for (size_t i = 0; i < children.size(); i++)
children[i].reset(new Node<Level - 1>());
array<unique_ptr<Node<Level - 1>>, 4> children;
;
template<>
class Node<0>
;
...
Node<2> root;
我需要创建一个节点树,其中每个节点,但最后一个(级别 = 0),有 4 个子节点。我想将孩子存储在std:array
的std::unique_ptr
中。
我的解决方案是正确的还是我做错了什么?有更聪明的方法来实现这个结果?
【问题讨论】:
好像可以直接使用std::array<Node<Level - 1>, 4>
。
@Jarod42 仅在理论上,如果不使用指针,我无法拥有太深的层次。
如果这确实是您想要实现的目标,那没关系。如果您打算对这 4 个子项中的任何一个使用编译时(而不是运行时)索引,则可以考虑将 std::array<Node,4>
更改为 std::tuple<Node,Node,Node,Node>
。
@Ethouris 看来 OP 可能会将其超出通常适合自动存储的范围,因此使用 std::unique_ptr
的原因。 std::array<Node,4>
在评论中;不是问题。例如,没有指针的 10 层深的树将消耗大约 27MB 的自动存储空间,这比大多数预留的实现要大得多。
@Ethouris 同质std::tuple
与std::array
相比几乎没有优势,std::array
也可以与std::get
等一起使用。
【参考方案1】:
我看不出这里有模板的价值。树是固定的,大小有限,你可以把它做成一个值类型。
例如一棵 4 级树,其叶节点包含 V
类型的值:
namespace Tree
template <typename V>
struct Root
struct Tier1
struct Tier2
struct Tier3
struct Leaf V value; ;
std::array<Leaf, 4> children;
;
std::array<Tier3, 4> children;
;
std::array<Tier2, 4> children;
;
std::array<Tier1, 4> children;
;
当然,如果节点可以在所有级别都是可选的,请使用boost::optional<>
:
std::array<optional<Leaf>, 4> children; ;
std::array<optional<Tier3>, 4> children; ;
std::array<optional<Tier2>, 4> children; ;
std::array<optional<Tier1>, 4> children;
如果你没有 boost,你可以在那里使用 unique_ptr
作为一个穷人的可选项(但这对内存布局有很大影响)。
再来一次,使用 feeling 模板:
你可以用模板表达同样的意思:
Live On Coliru
#include <array>
#include <boost/optional.hpp>
namespace Tree
using boost::optional;
template <typename LeafValue, int level> struct Node;
template <typename LeafValue> struct Node<LeafValue, 3>
LeafValue value;
;
template <typename LeafValue, int level> struct Node
std::array<optional<Node<LeafValue, level+1> >, 4> children;
;
template <typename LeafValue> using Root = Node<LeafValue, 0>;
int main()
Tree::Root<int> a =
;
【讨论】:
如果编译器在链接器中具有良好的 ICF,代码大小只会在存在实际差异的情况下增加。不可否认,大多数编译器都缺乏 ICF 支持(相同的 comdat 折叠),除了 MSVC 和 gcc 的 Gold 链接器(最后我检查过)。 @Yakk 我错过了关于代码/二进制大小的评论吗? 我想我在你的回答中读到了一些关于“复制方法”之类的东西。我在编辑历史中看不到它,所以也许我产生了幻觉。 @Yakk 我只是对模板的模板持怀疑态度。但是请注意我是如何为LeafValue
添加类型参数的。因为那个对我来说确实有意义以上是关于模板类的树,其中 chilldren 是 std::array of std::unique_ptr的主要内容,如果未能解决你的问题,请参考以下文章