尼斯特布尔向量类

Nestable Vector Class

本文关键字:向量 布尔      更新时间:2023-10-16

我正在做一个项目,我需要能够拥有一种特定的数据结构。从本质上讲,我需要能够有一个向量,它可以存储整数作为元素,或者另一个向量。然后同样的想法需要应用于第二个向量。我知道这相当于让容器包含自身,但我想知道是否有某种方法可以做到这一点。

也许一个例子会澄清。我希望能够拥有这样的集合:

[[1,2], [[3,4], 5], [6, 7]] 

我的想法是我可以无限深入地在"系列"和"并行"处进行整数和向量。我知道这是一个艰难的问题,但有什么办法可以做到这一点。我的一个想法是,我们可以有一个向量,其中 Elem 是我们定义的一个类,其中包含一个表示其嵌套深度的 int,以及一个指向堆分配元素的 void* 指针。

我觉得这里有一些多态魔法可以完成,但不太确定。

一些提升魔法怎么样?

#include <vector>
#include <boost/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
// A recursive tree structure made of std::vector.
template< typename T, class Allocator = std::allocator<T> >
struct vector_tree :
std::vector< 
boost::variant< T, boost::recursive_wrapper< vector_tree< T, Allocator > > >,
Allocator >
{
using base = std::vector< 
boost::variant< T, boost::recursive_wrapper< vector_tree< T, Allocator > > >,
Allocator >;
// Forward all constructors of the base class.
using base::base;
};

此类型允许无限嵌套,并具有非常干净的初始化语法。

使用示例

using mytree = vector_tree<int>;
// Construct a nested vector_tree with initializer list.
mytree tree{
1,
2,
mytree{ 
mytree{ 3, 4, 5 },
6, 
}
};
// Add more stuff.
tree.push_back( 42 );
tree.push_back( mytree{ 43, 44 } );
// Add something to a child vector_tree. 
// NOTE: boost::get() will throw a boost::bad_get exception if requested type is invalid
boost::get<mytree>( tree[ 2 ] ).push_back( 99 );
// To avoid the boost::bad_get exception, we can check if the child actually is a vector_tree:
if( mytree* pchild = boost::get<mytree>( &tree[ 2 ] ) )
{
(*pchild)[ 1 ] = 88;
}

科利鲁的现场演示。

解释

boost::recursive_wrapper是必需的,因为boost::variant通常需要完整的类型,但在声明时vector_tree仍然不完整。

boost::recursive_wrapper实际上没什么魔术。它只是一个指针的包装器!众所周知,可以为不完整的类型声明指针而不会出现问题。这个包装类只是隐藏了通过处理分配、释放和提供值语义来使用指针的事实。它具有boost::variant的特殊支持,使包装器完全透明,因此可以像根本没有包装器类一样使用该变体。

注意:自 C++17 以来,有std::variant但 AFAIK 没有可以透明处理嵌套的boost::recursive_wrapper等效项。

如果你想使用多态性,你可以定义一个基struct,并从中派生一个包含std::vector<*base>的结构,并派生另一个包含int的结构。main 函数将包含第一个派生类的实例,该实例可能包含指向自身的指针,或第二个派生类。这将允许包含 int 的向量中的向量。

若要存储深度等信息,可以在基结构中有一个int depth,构造函数将在其中传递当前深度并添加一个深度。

以下是您要查找的内容:

template <typename T>
class NestableVector {
private:
struct element {
virtual element* copy() const = 0;
};
struct vector_element : public element {
NestableVector value;
element* copy() const;
};
struct normal_element : public element {
T value;
element* copy() const;
};
class copy_ptr { // specialized smart pointer that copies underlying object when copied
private:
element* ptr;
public:
copy_ptr(element*);
copy_ptr(const copy_ptr&); // copies *ptr into new object
void operator=(const copy_ptr&); // same as above
};
std::vector<copy_ptr> v; // underlying vector
public: 
// interface to v here
};

定义具有两个子类(vector_elementnormal_element)的特殊element类型。这两者都重载基类的copy()函数,该函数用于新的智能指针类copy_ptr,该函数复制复制时它本身指向的元素。我们使用智能指针,以便在v中复制内容时,元素本身被复制,而不是指向它们的指针。