构造不同类型的C ++向量数组

时间:2018-06-26 15:51:25

标签: c++ vector types

有没有一种很好的方法来构造不同类型的std :: vector数组?还有存储这些向量的好方法吗?

例如,让我们有一些结构FooBarBaz。我想制作一个容器类Cont,其中包含FooBarBaz向量的某种组合。以下代码将实现此目的,但是我有一些问题。

#include <vector>

// arbitrary structs
struct Foo{ int var1; };
struct Bar{ double var1; double var2; };
struct Baz{ char var1; float var2; };

enum Mask{
    fooMask = (1<<0),
    barMask = (1<<1),
    bazMask = (1<<2)
};

class Cont{
    void** containers;

public:
    Cont(int mask){
        // count number of 1s in mask
        int count = 0;
        int countMask = mask;
        while(countMask){
            countMask &= countMask-1; // unset rightmost 1
            count++;
        }

        containers = new void*[count];

        int index = 0;
        if((mask & fooMask) == fooMask)
            containers[index++] = new std::vector<Foo>;
        if((mask & barMask) == barMask)
            containers[index++] = new std::vector<Bar>;
        if((mask & bazMask) == bazMask)
            containers[index++] = new std::vector<Baz>;
    }
};

int main(){
    // example construction
    Cont c1(fooMask);
    Cont c2(barMask|bazMask);

    return 0;
}

首先,我不喜欢将向量数组存储在void **中,但我找不到更好的方法。

第二,如果我添加一个名为Qux的新结构,则必须修改Cont构造函数。最好是出于可维护性,我希望构造数组而不必将结构类型硬编码到Cont类中。

我尝试使用模板来解决此问题,但是找不到我满意的解决方案。我担心将Cont用作模板,因为我认为它将导致每个结构组合的模板膨胀。另外,我将有多个Cont对象,但是我需要的每个组合中只有一个。

1 个答案:

答案 0 :(得分:2)

您可以使用类型擦除。

struct ContainerBase
{
  virtual ~ContainerBase() = 0;
  // This is where you can add an interface for common functionality.
  // Write the pure virtual functions here and implement/override them in ContainerTyped.
};

inline ContainerBase::~ContainerBase() = default;

template<class T>
struct ContainerTyped : public ContainerBase
{
  std::vector<T> values;
};

class Cont
{
  std::vector<std::unique_ptr<ContainerBase>> containers;

public:
  Cont(int mask) {
    // ...
    if ((mask & fooMask) > 0)
      containers.push_back(std::make_unique<ContainerTyped<Foo>>());
    if ((mask & barMask) > 0)
      containers.push_back(std::make_unique<ContainerTyped<Bar>>());
  }
};

Demo

这可能比使用例如std::any或其他先前存在的类型擦除,因为1)您指定只能存储特定的事物(您的矢量容器),并且2)您可以按指示添加通用接口,甚至专门使用不同的{ 1}}。但是我们需要更多地了解您的用例,以详细说明这种好处。

ContainerTyped的问题始终是,您需要以某种方式保留有关实际存储内容的信息,因为您正在绕过强类型系统。换句话说,如何将存储的 back 返回到强类型系统中?这正是上述方法可以发挥作用的部分,因为您可以在void*中添加virtual print() = 0,然后为每种结构(例如

)创建专用版本
ContainerBase

就添加一个template<> void ContainerTyped<Foo>::print() { for (Foo& foo : values) { // Print Foo objects as you wish! } } 结构时不必触摸Cont构造函数而言,显然您仍然需要以某种方式对“哪个掩码位属于哪个结构”的信息进行编码,但是您可以从Qux构造函数中提取出来(甚至将其隐藏在其他翻译单元中):

Cont

您可以采用其他方式来枚举枚举->类型信息,但这超出了此问题的范围。关键是您可以将具体类型隐藏在// Put this implementation wherever, Cont only has to know the signature. std::unique_ptr<ContainerBase> makeContainer(int mask, unsigned indexBit) { if ((mask & fooMask) > 0) return std::make_unique<ContainerTyped<Foo>>(); // etc. if ((mask & quxMask) > 0) return std::make_unique<ContainerTyped<Qux>>(); return nullptr; } // ... Cont::Cont(int mask) { for (unsigned indexBit = 0; indexBit < 8; ++indexBit) { auto container = makeContainer(mask, indexBit); if (container) containers.emplace_back(std::move(container)); } } 后面,并在要引用“这些容器中的任何一个”的地方使用它。