一个数组,多种类型
One array, multiple types
我有一个数组,它是FIFO列表,我正在将数据记录添加到其中。
我的数据记录可以是任何标准类型(字符串、字符、整数、长整型、无符号、浮点数、双精度),我使用函数将其推送到我的数组。
我想稍后按添加顺序读取该数据记录。
这是我尝试过的:
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(...);
....
由于您只能使用标准库,因此您需要自己实现解决方案或使用现有的易于适应的解决方案。您要查找的内容称为标记联合或变体。这是一种数据结构,其中包含一个在同一位置保存多种类型数据的union
,以及一个联合外部的单独值,用于指示哪个元素处于活动状态/已使用状态。
对于整型类型,这是相当合理的,因为您只需要为设置和检索值提供原始支持。对于更复杂的类型,如std::string
和std::vector
如果您不使用 C++11,事情会变得更加困难。这是因为在 C++11 之前,union
不能包含具有非平凡复制构造函数、非平凡析构函数或非平凡复制赋值运算符的类型。
注释(此处和此处)中提供的示例any
类似乎是合理且完整的实现,但需要 C++11。两者都仅依赖于标准库中的组件,因此它们可能是可行的解决方案。但是,如果您不使用 C++11 或需要更简单的解决方案来基于您的解决方案,我在下面提供了一个示例。它处理char
、int
和double
类型,所以如果你需要支持更复杂的类型,你需要添加它们。对于复杂类型(没有 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
}
使用联合,就像另一个答案中建议的那样,是最直接的解决方案。作为替代方案,我想提出一种我认为更加面向对象的方法。这个想法是为值定义一个抽象基类,该基类定义值所需的所有操作,然后为每种类型的值定义一个派生类:
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"));
需要注意的一件事是容器包含指针,并且值是动态分配的。这意味着在销毁容器时不会自动释放这些值。因此,您必须在容器被销毁时手动删除元素,或者使用某种形式的智能指针而不是裸指针作为存储在容器中的类型。
主要好处是你没有一个处理所有可能类型的类。相反,它们被很好地隔离了。例如,可以通过简单地实现新类来添加对新类型的支持,而无需更改任何现有代码。
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 模板元程序查找相似的连续类型名称
- 任何种类的分数 在任何类型的订单中
- 2 种模板相关类型种类的差异
- C++每帧更新和复制一系列值.我应该使用哪种类类型
- 在键上使用 map.find() 和 count(),这是一种类对象类型