从非模板化接口检索'generic'数据
Retrieve 'generic' data from non-templated interface
目标是为数据创建一个通用容器,它允许我使用以下内容:
std::vector<GenericContainer> containerList = {"foo", 1.4f, 10, 'a'};
我已经写了以下代码*:
struct GenericContainer
{
template <typename DataType>
GenericContainer(DataType && data) :
_base(new Derived<DataType>(std::forward<DataType>(data)))
{ }
// operates with the data
void func()
{
_base->func();
}
struct Base
{
virtual void func() = 0;
virtual ~Base() = default;
};
template <typename T>
struct Derived : public Base
{
Derived(T && data) :
_data(std::forward<T>(data))
{}
void func() override
{
process(_data);
}
T _data;
};
Base * _base;
};
这里process
可以是一个自由函数,方便地为每种类型定义。
void process(const float& f) { /**/ }
void process(const int& i) { /**/ }
// ...
我的问题是:是否有一种优雅的方法可以从GenericContainer中恢复原始类型的数据(不使用stringstream
之类的东西来处理数据)。
我的猜测是,可以通过将函子的某种模板struct
传递给GenericContainer
来完成,但我在这一点上陷入了困境。
*代码的灵感来源于本文。
一个C++对象类似于boost::any
,它可以在类似值的上下文中存储任何类型的数据,并且如果您提供完全相同的类型,就可以将其取出。
boost::any
是类型擦除的一个例子,在这里,您"忘记"了关于类型的许多细节,只记得某些操作。在any
的情况下,即复制、销毁并强制转换回同一类型。
在你的情况下,除了process
和destroy,你已经忘记了一切。
运行时概念是该技术的另一个名称。
boost::variant
是另一种方法,它存储类型列表中的一个,并提供"访问"所包含数据的方法。因为它知道它存储的类型列表,所以它可以键入传入的check函数对象,并确保它们可以使用存储的每个数据的类型。然后在运行时,它可以选择调用哪一个。
一般来说,若您启用了RTTI(许多编译器提供了删除它的选项),添加"强制转换回同一类型"相对容易。在您的情况下,只需在容器上对Derived<T>
执行dyanmic_cast
,如果有效,只需获取其中包含的_data
。这样的强制转换通常应该允许失败。
如果你知道你期望的类型(或类型列表),这可以让你把它拿出来。如果您不知道类型,则只能运行在构造时删除的代码。理论上,类型擦除的数据可能来自完全独立于要在该类型上运行的代码编写的DLL;并且C++不随每个可执行文件一起提供编译器。
顺便说一句,你的GenericContainer(DataType && data)
有一个危险的签名;您正在转发引用,因此这可能意味着您的GenericContainer
最终可能会存储对DataType的引用。通常,类型应该是值语义或引用语义;在它们之间无声地切换类型将导致意外的行为。
template<class T>
T* as() {
auto* d = dynamic_cast<Derived<T>*>(_base);
if (!d) return nullptr;
return std::addressof(d->_data);
}
template<class T>
T const* as() const {
auto const* d = dynamic_cast<Derived<T>*>(_base);
if (!d) return nullptr;
return std::addressof(d->_data);
}
上述方法将启用GenericContainer c; int* i = c.as<int>();
,并且i
为nullptr,如果c中没有int
。
- 防止主数据类型C++的隐式转换
- 用于访问容器<T>数据成员的正确 API
- 嵌套在类中时无法设置成员数据
- 使用流处理接收到的数据
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 在cuda线程之间共享大量常量数据
- C++将文本文件中的数据读取到结构数组中
- 如何在C++中序列化结构数据
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 在c代码之间共享数据的最佳方式
- 链表,反向函数,数据结构
- 数据成员SFINAE的C++17测试:gcc vs clang
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 如何对点云数据进行排序
- 从矢量<无符号字符>转换为字符* 包括垃圾数据
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- 从非模板化接口检索'generic'数据