容器杂项类型 - C ++

时间:2015-01-27 20:28:12

标签: c++ templates c++11 generics containers

所以我试图创建一个"表" C ++中的类,结构如下:

Table.h

class Table
{
private:
    class TableImpl;
    TableImpl* impl;
};

Table.cpp

class Table::TableImpl
{
private:
    class Row
    {
    private:
        template <typename T>
        class RowDataCell
        {
            T data;
        }
        std::vector<RowDataCell*> data;
    };
    std::vector<Row*> rows;
};

TableImplstd::vectorRow个对象组成,每个Row个对象由std::vector个通用RowDataCell个对象组成。唯一的问题是,我无法创建std::vector,因为我需要为RowDataCell*提供一个模板参数,这将阻碍我有一个容器杂项对象的目标。

使用标准C ++是否有办法实现这一目标。

3 个答案:

答案 0 :(得分:4)

有两种合理的方法。

第一个是区别性联盟,另一个是旧C风格void*&#34的类型安全变体;任何东西都可以在这里&#34;。

我首先提到它们的两个boost实现:

boost::variant<A,B,C>(和传入的std::experimental::variant)是一个有区别的联盟。它可以存储ABC类型的内容。有各种类型安全的方法来获取元素,或通过&#34;访问&#34;对它们执行操作。 Variant对它可以容纳的类型有一些限制,并且取决于你如何注入这些类型的更多限制。

boost::any(和传入的std::experimental::any)是一个具有值语义的类型安全的void*。几乎任何东西都可以存储在其中(any要求你的对象是CopyConstructable),但只有你知道存储在其中的东西的确切类型并且要求它才能访问它。

自己编写任何一个都是可行的,但我建议使用它们,或者至少理解它们并克隆其界面和模式的大部分内容。

variant可以存储实例&#34;内部&#34;在其内部,通常是一种更好的方法。您可以使用union,类型列表和该列表的索引来模拟它,以及一堆元编程样板。另外,对齐问题很棘手。

any更容易编写,但仍然有点挑战。它是一个非常基本的类型擦除对象,只有&#34;强制转换为X&#34; (通过typeid或同等学历)并复制公开。如果你曾经看到std::function被实施,你就到了一半。

答案 1 :(得分:0)

是的,有一种标准的C ++方式来实现记录表,它可能会变得丑陋。我试过了。

我们假设一个表是记录的容器 记录可以包含字段或记录 字段可以是不同的类型,例如整数,字符串和BLOB。

至少在我看来,目标是尽可能保持事物的通用性,直到最低级别,即专业领域。这意味着字段值通过字符串传递。

所以,这是一个简化的模型:

struct Component; // The base of everything.
struct Record : public Component {
  std::vector<Component *> components;
};
struct Field : public Component {
  std::string  name;
  virtual std::string  get_value_as_string(void) = 0;
};
struct Field_String : public Field;
//... And so on.
struct Table {
  std::vector<Record *> rows;
};

基本问题是表格的每个单元格都可能具有不同的类型。该表可以有无限的列和行。

我还建议阅读有关数据库的内容。许多数据库接口都可以解决表的问题。

答案 2 :(得分:0)

有几种方法可以做你想要的。一种方法是为要放入容器的类型定义一个公共接口,然后将指向该接口的指针放入向量中:

class RowDataCellInterface
{
public:
    virtual ~RowDataInterface() {}
    virtual std::string toString() const = 0;
    virtual std::unique_ptr<RowDataInterface> clone() const = 0;
};

然后,您甚至可以以模板化的方式派生此接口的实现:

template <typename T>
class RowDataCell final : public RowDataCellInterface
{
public:
    virtual std::string toString() const
    { 
        std::stringstream ss; 
        ss << data; 
        return ss.str();
    }

    virtual std::unique_ptr<RowDataInterface> clone() const
    {
        std::make_unique<RowDataCell>(*this);
    }

private:
    T data;
};

现在可以把这些东西放到这样的矢量中:

std::vector<std::unique_ptr<RowDataCellInterface>>

一切都应该正常。要复制矢量,您应该使用界面的clone()成员函数。有几种图书馆解决方案可以帮助您实现您想要的目标。其中一个是boost::variant,我建议。我对一个非常相似的问题here做了非常详细的回答。另一个库解决方案是boost::any,一开始可能看起来更简单,但是为了用它做一些有意义的事情,你必须知道所包含事物的类型,它在访问时被删除。我希望大多数情况下boost::variant超过boost::any