我正在从一个文件中阅读数据,数据的类型被存储为uint8_t
,它指示我将要读取的数据的类型。这是与这些值的声明相对应的枚举。
enum DataType
{
kInt8,
kUint16,
kInt16,
kUint32,
kInt32,
kUint64,
kInt64,
kFloat16,
kFloat32,
kFloat64
};
然后,我得到一个函数,它读取存储在文件中的特定类型的值,如下所示:
template<typename T>
readData(T*& data, size_t numElements)
{
ifs.read((char*)data, sizeof(T) * numElements);
}
uint8_t type;
ifs.read((char*)&type, 1);
uint32_t numElements;
ids.read((char*)&numElements, sizeof(uint32_t));
switch (type) {
case kUint8:
uint8_t* data = new uint8_t[numElements];
readData<uint8_t>(data, numElements);
// eventually delete mem
...
break;
case kUint16:
uint16_t* data = new int16_t[numElements];
readData<uint16_t>(data, numElements);
// eventually delete mem
...
break;
case ... etc.
default:
break;
}
我刚刚介绍了两种情况,但最终,您需要对所有类型都这样做。这是大量的代码重复,所以我想做的是在给定枚举值的情况下找到值的实际类型。例如,如果枚举值是kUint32
,则类型将是uint32_t
,等等。如果我能够做到这一点,代码可以变得更加紧凑,类似于以下代码(伪代码):
DataType typeFromFile = kUint32;
ActualC++Type T = typeFromFile.getType();
readData<T>(data, numElements);
你能推荐什么技术来使它工作(或者你能推荐什么替代解决方案?)。
3条答案
按热度按时间4nkexdtk1#
你试图获取一个运行时值,并将其Map到编译时类型。由于C++是一种编译时类型化语言,因此,在某些时候,你不得不做一些像switch/case语句这样的事情。这是因为每个选项都需要有自己的独立代码。
因此,我们的愿望是尽可能减少您实际执行的操作量。使用标准库工具执行此操作的最佳方法是使用
variant
。因此,您创建了一个
variant<Ts>
,使Ts
类型为unique_ptr<T[]>
,其中各个T
是枚举中的类型序列 * 按顺序 *。这样,枚举索引与variant
索引匹配。unique_ptr
部分很重要,因为它将使variant
为您销毁数组,而不必知道它存储的是哪种类型。所以
switch/case
唯一需要做的事情就是创建数组。数组的处理可以在访问者中进行,访问者可以是一个模板as follows:oxcyiej72#
我将使用higher-order macro来处理这类事情。首先使用一个宏来定义枚举值和类型之间的Map:
然后使用它为所有枚举值和类型生成
switch
语句:57hvy0tb3#
除了其他答案之外,另一种方法是首先定义一个编译时类型列表,然后根据类型分配枚举值(这可以防止列表与枚举顺序问题),并使用
id<type>
调用lambda: