一个阵列,多种类型

时间:2015-01-03 23:16:01

标签: c++ arrays type-conversion

我有一个FIFO列表数组,我将数据记录添加到 我的数据记录可以是任何标准类型(string,char,int,long,unsigned,float,double),我使用函数将其推送到我的数组。
我想稍后读取数据记录,以便添加它们。

这就是我的尝试:

class List
{
    typedef std::pair<typename, std::vector<char>> Record; // typename ??

    public:
        template <typename T>
        void addRecord(T value)
        {
            char* arr = reinterpred_cast<char*>(&value);  // Casting ?
            // Convert to Record and push to _records
        }

        template <typename T>
        T getRecord(std::vector<Record>::iterator record) const
        {
            // Convert Record to T and return 
        }

    private:
        std::vector<Record> _records;
}

如何从这些类型转换为字节数组,还是有其他方法可以做到这一点?

示例方法我想使用它:

List list;
list.addRecord("Test string");
list.addRecord(10);
list.addRecord(999999);
list.addRecord("Test string 2");
list.addRecord('X');
...

然后以同样的方式阅读它们:

std::string testString = list.getRecord(...);
char testChar = list.getRecord(...);
int testInt = list.getRecord(...);
....

2 个答案:

答案 0 :(得分:3)

由于您只能使用标准库,因此您需要自己实施解决方案或使用现有的易于适应的解决方案。您要查找的内容称为tagged union或变体。这是一个数据结构,其中包含union以在同一位置保存多种类型的数据,在联合之外的单独值,以指示哪个元素处于活动/使用状态。

对于整数类型,这是完全可以管理的,因为您只需要为设置和检索值提供原始支持。对于更复杂的类型,如std::stringstd::vector,如果您不使用C ++ 11,事情会变得更加困难。这是因为在C ++ 11之前,union不能包含具有非平凡复制构造函数,非平凡析构函数或非平凡复制赋值运算符的类型。

评论(herehere)中提供的两个示例any类似乎都是合理且完整的实现,但需要C ++ 11。两者都只依赖于标准库中的组件,因此它们可能是您可行的解决方案。但是,如果您不使用C ++ 11或需要更简单的解决方案来构建解决方案,我已在下面提供了示例。它处理charintdouble类型,因此如果您需要支持更复杂的类型,则需要添加它们。在复杂类型(并且没有C ++ 11)的情况下,您需要保持指向实例的指针并自己管理生命周期(手动或使用智能指针)。您还需要根据您的特定需求(深拷贝和浅拷贝)处理复制和分配。

简单标记联合:

struct TaggedUnion
{
    enum Type
    {
        Char,
        Int,
        Double
    };


    TaggedUnion(const char& value) : type(Char), value(value) {}
    TaggedUnion(const int& value) : type(Int), value(value) {}
    TaggedUnion(const double& value) : type(Double), value(value) {}

    Type getType() const { return type; }
    char getChar() const { assert(type == Char); return value.getChar(); }
    int getInt() const { assert(type == Int);  return value.getInt(); }
    double getDouble() const { assert(type == Double);  return value.getDouble(); }


private:

    union Union
    {
        Union(const char& value) : charValue(value) {}
        Union(const int& value) : intValue(value) {}
        Union(const double& value) : doubleValue(value) {}

        char getChar() const { return charValue; }
        int getInt() const { return intValue; }
        double getDouble() const { return doubleValue; }

    private:

        char    charValue;
        int     intValue;
        double  doubleValue;
    };

    Type type;
    Union value;
};

使用示例:

#include <iostream>
#include <vector>
#include <cassert>

int main()
{
    std::vector<TaggedUnion> values;

    values.push_back(TaggedUnion(0.0));    //  Store double/float
    values.push_back(TaggedUnion(0));       //  Store int
    values.push_back(TaggedUnion(' '));     //  Store char
}

答案 1 :(得分:0)

使用联合,就像另一个答案中建议的那样,是最直接的解决方案。作为替代方案,我想建议一种我认为更加面向对象的方法。我们的想法是为您的值定义一个抽象基类,它定义值所需的所有操作,然后定义每种类型值的派生类:

class Value {
public:
    virtual ~Value() {}

    // Define operations needed for values, e.g.
    virtual void print() = 0;
};

class IntValue: public Value {
public:
    IntValue(int val) : m_val(val) {}

    virtual void print() {
        std::cout << m_val;
    }

private:
    int m_val;
};

class StringValue: public Value {
public:
    StringValue(const std::string& val) : m_val(val) {}

    virtual void print() {
        std::cout << m_val;
    }

private:
    std::string m_val;
};

// Equivalent class definitions for other value types.

然后,构建一组值:

std::vector<Value*> values;
values.push_back(new IntValue(42));
values.push_back(new StringValue("Hello"));

要注意的一件事是容器包含指针,并且值是动态分配的。这意味着在销毁容器时不会自动释放这些值。因此,您必须在销毁容器时手动删除元素,或使用某种形式的智能指针而不是裸指针作为存储在容器中的类型。

主要好处是您没有一个类可以处理所有可能的类型。相反,他们很好地孤立。例如,您可以通过简单地实现新类来添加对新类型的支持,而无需更改任何现有代码。