簡體   English   中英

如何在C ++中實現具有不同列數據類型的數據表

[英]How to implement a data table with different column data types in C++

我想實現一個數據表,其中字段可能有不同的類型。 一個字段可以是字符串的向量。 另一個字段可以是浮點數的向量。 並且在編譯時字段的類型是未知的,因為我希望能夠從csv文件構造數據表。

我怎么能用C ++做呢?

使用boost::variant ,它可以代表一組類型中的一種:

std::vector<boost::variant<std::string, float>> values;

然后,您可以將訪問者應用於變體:

struct visitor_t : boost::static_visitor<> {
    void operator()(std::string const& x) const {
        std::cout << "got string: " << x << '\n';
    }

    void operator()(float x) const {
        std::cout << "got float: " << x << '\n';
    }
};

visitor_t visitor;
for (auto&& value : values) {
    boost::apply_visitor(visitor, value);
}

實例!

我嘗試過類似的東西:

class Component;

class Field : public Component
{
  // Common interface methods
  public:  
    virtual std::string get_field_name() const = 0;
    virtual std::string get_value_as_string() const = 0;
};

class Record : public Component
{
  // Common interface methods
  std::vector< std::unique_ptr<Component> > fields;
};

class Integer_Field : public Field;

想法是Record可以包含各種字段。 各個字段由指向Component基類的指針實現。 這允許記錄包含子記錄。

你應該看到Sean Parent談論“ 繼承是邪惡的基礎” 您可以在打印格式看到它在這里 ,在“值語義和基於概念的多態性。”

他提出了一個基於概念的對象類,它定義了容器元素的接口。 任何滿足所需接口的對象(即具有所需的獨立功能)都可以放入容器中。

您可以通過查看下面的代碼示例(取自我上面鏈接的文檔)來獲取要點。

class object_t {
  public:
    template <typename T>
    object_t(T x) : self_(make_shared<model<T>>(move(x)))
    { }

    friend void draw(const object_t& x, ostream& out, size_t position)
    { x.self_->draw_(out, position); }

  private:
    struct concept_t {
        virtual ~concept_t() = default;
        virtual void draw_(ostream&, size_t) const = 0;
    };
    template <typename T>
    struct model : concept_t {
        model(T x) : data_(move(x)) { }
        void draw_(ostream& out, size_t position) const 
        { draw(data_, out, position); }

        T data_;
    };

   shared_ptr<const concept_t> self_;
};

你的每個字段都是這些object_t類型之一,它們可以采用任何類型( std::vector<int>std::deque<float>std::string等)。 你只需要確保你想要為object_t支持的任何方法(在這個例子中,它只是draw() )都是為你的不同輸入定義的。 這很好,因為它為您提供了值語義,並且使添加新類型變得非常簡單。

由於數據類型在編譯時是未知的,因此必須在運行時構造和存儲該信息。 對於每行的每個字段,可能有三條信息要編碼:

  1. 字段的類型。
  2. 字段的值(必須與#1中指定的類型匹配)
  3. (可選)字段的名稱。

你可以使用多態類型, boost::anyboost::variant (或std::anystd::variant ,如C ++ 17中所定義),但是需要一個更優雅,更強大且更節省內存的解決方案每行具有相同結構的優點。

你在做什么基本上是創建一個數據庫程序。 在數據庫中, 模式對數據結構進行編碼,但與數據本身是分開的。 你想要的是一種在運行時編碼模式的方法,如下所示:

enum class FieldType {
  // Scalar types:
  Boolean, Integer, FloatingPoint, String,

  // Array types:
  ArrayBit = 0x1000, // This bit set for array types
  Boolean_Array = Boolean | ArrayBit,
  Integer_Array, FloatingPoint_Array, String_Array
};

class FieldSchema {
  FieldType   m_type;
  std::string m_name;  // Optional, if fields are named
  ...
};

class RowSchema {
  std::vector<FieldSchema> m_fields;
  ...
};

數據字段本身只是可能的數據類型的聯合。 (請注意,將字符串或向量放入聯合需要C ++ 11或更高版本。)

union FieldValue {
  bool                     m_boolean;
  int                      m_integer;
  double                   m_floatingpoint;
  std::string              m_string;
  std::vector<bool>        m_boolean_array;
  std::vector<int>         m_integer_array;
  std::vector<double>      m_floatingpoint_array;
  std::vector<std::string> m_string_array;

  // Constructors for each type go here
};

數據行只是數據字段的向量,帶有指向模式的指針:

class RowValue {
  RowSchema*               m_schama;
  std::vector<FieldValue>  m_fields;
  ...
};

現在,對於每個CSV文件,整個表將有一個RowSchema對象,但每行有一個RowValue對象。 給定文件的所有RowValue對象將共享(指向)相同的RowSchema對象。 讀取CSV文件的過程是:

  1. 確定所有行的結構(模式)(可能通過讀取第一行)。
  2. 構建反映該結構的RowSchema對象。
  3. 對於每一行:創建一個指向步驟2中的RowSchemaRowValue對象; 將每個字段讀入相應FieldSchema指定的正確數據類型; 並使用emplace_back將值附加到m_fields數組的emplace_back

由於這是一個Stack Overflow的答案,而不是關於C ++ 11的教科書,我不會詳細介紹如何構建包含字符串或向量的聯合,也不會介紹如何使用vector::emplace_back 所有這些信息都可以在其他地方獲得(例如, cppreference.com )。 這也可以在C ++ 03中完成,還可以模擬非平凡類型的並集(例如,通過使用boost::variant )。

顯然,我遺漏了很多細節。 我要提到的一個警告是, FieldValue的析構函數不足以銷毀union中包含的字符串或向量。 相反,您必須在模式中查找數據類型並顯式調用該字段的正確析構函數。 因此, RowValue的析構RowValue必須迭代字段並單獨銷毀每個字段。 一個C ++ 17 std::variant (或boost::variant )在這里會有所幫助,代價是額外的內存。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM