稳定的矢量类

时间:2017-04-29 22:17:06

标签: c++ data-structures polymorphism

我正在开发一个项目,我需要能够拥有特定类型的数据结构。本质上,我需要能够有一个向量,它可以存储整数或其他向量。然后同样的想法需要应用于第二个向量。我知道有一个容器包含自己,但我想知道是否有某种方法可以做到这一点。

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

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

我认为我可以在“系列”和“平行”无限期地进行整理和向量。我知道这是一个棘手的问题,但是有什么方法可以做到这一点。我的一个想法是我们可以有一个向量,其中Elem是我们定义的一个类,它包含一个表示它的嵌套深度的int,以及一个指向堆分配元素的void *指针。

我觉得这里可以做一些多态魔术,但不太确定。

3 个答案:

答案 0 :(得分:3)

某些boost魔法怎么样?

#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;
}

Live Demo on Coliru.

说明

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

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

注意:由于C ++ 17有std::variant但是AFAIK没有boost::recursive_wrapper等效的,可以透明地处理嵌套。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

以下是您正在寻找的内容:

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
};

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