我正在编写一些代码来获取如下所示的数据:
enum data_type { INT16 = 0, INT32, UINT64, FLOAT, TIMESTAMP };
struct buffer {
data_type element_type;
size_t size; // in elements of element_type, not bytes
void* data;
}
(这是简化的;实际上在这个结构中还有很多类型,更多字段等)
现在,我发现自己编写了一堆实用程序代码以在编译时将枚举值“转换”为实际类型,反之亦然。然后我意识到我需要做一些我需要在运行时做同样的事情,并且使用可变数量的缓冲区......所以现在,除了基于类型特征的值和枚举查找之外 -基于模板参数的类型查找 - 我正在编写查找 std::type_info
的代码。有点乱。
但实际上 - 我不应该这样做。它是重复的,我绝对确定我正在重新发明轮子 - 实现已经写过很多次的东西:编译器、DBMS、数据文件解析器、序列化库等等。
我能做些什么来尽量减少我在这项工作上的浪费?
注意事项:
- 我在运行时获取这些缓冲区,不能只在编译时取消删除类型(例如使用 type_traits)。
- 我无法更改 API。或者更确切地说,我可以在代码中更改任何我想要的内容,但我仍然会在内存中获取此布局中的数据。
- 我不只是将这些缓冲区作为输入,我还需要将它们作为输出。
- 我偶尔需要同时处理许多不同的缓冲区 - 甚至数量可变(例如
foo(buffer* buffers, int num_buffers);
。 - C++11 解决方案优于较新的标准版本。
- 我实际上经常使用
gsl
,所以如果您愿意,可以在您的答案中使用它。至于 Boost - 这在政治上可能难以依赖,但我想就 StackOverflow 问题而言,这很好。
最佳答案
这里的目标应该是尽快回到 C++ 类型系统。为此,应该有一个中央函数根据(运行时)data_type
进行切换,然后将每个案例交给一个(编译时)模板版本。
您没有说明相关函数的外观,但这里有一个示例:
template<typename T>
struct TypedBuffer
{
TypedBuffer(void* data, size_t elementCount) { /* ... */ }
// ...
};
template<typename T>
void handleBufferTyped(void* data, size_t elementCount)
{
TypedBuffer<T> buf(data, elementCount);
// Do whatever you want - you're back in the type system.
}
void handleBuffer(buffer buf)
{
switch (buf.element_type)
{
case INT16: handleBufferTyped<int16_t>(buf.data, buf.size); break;
case INT32: handleBufferTyped<int32_t>(buf.data, buf.size); break;
case UINT64: handleBufferTyped<uint64_t>(buf.data, buf.size); break;
case FLOAT: handleBufferTyped<float>(buf.data, buf.size); break;
case TIMESTAMP: handleBufferTyped<std::time_t>(buf.data, buf.size); break;
}
}
如果需要,您还可以让 TypedBuffer
从非模板基类继承,这样您就可以多态地从 handleBuffer
返回,但这混合了很多范例,可能不必要。
关于c++ - 在运行时处理类型删除的数据 - 如何不重新发明轮子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53080705/