我喜欢编码,并且由于其简单性和强大功能,通常在Python中也是如此。
但是,对于一些时间紧迫的程序/任务,我使用C ++。
因此,为了两全其美,我在C ++中列出了Pythonesque。
AIM:我希望能够添加任何数据类型的任何变量或值,包括用户定义的类。
为此,我有一个结构item
,其中有一个char * value
,一个char * type
和一个int size
。
我的List
具有这些item *
的数组。
现在,我已将变量包含在模板函数中:
template<class T> item * encode(const T& var);
并声明了指向项目item * i = new item;
而且,我将这些变量的值存储为c样式字符串。
例如,二进制文件中的14675
是0000 0000 0000 0000 0011 1001 0101 0011
因此,我已经动态创建了空间,如下所示:
i->size = sizeof(var);
i->value = new char[i->size]; //4 in this case
并用var中的各个位设置值中的每个位。
我也将它们的类型存储为
i->type = typeinfo(var).name();
到目前为止一切顺利!
现在,我被auto decode(item * i) -> decltype(/*What goes here???*/)
困住了
如何指定函数的返回类型?
有什么办法吗?
最好使用i->type
?
还是应该更改此过程的基本设计?
预先感谢!
答案 0 :(得分:0)
我希望能够添加任何数据类型的任何变量或值,包括用户定义的类。
没有用户的合作,这在C ++中是不可能的。
请记住,C ++类型仅是编译时概念。它们在运行时不存在。在运行时唯一可用的类型信息是typeid()
提供的RTTI薄层。像Python中那样的运行时鸭子输入是不可能的。
您可以很容易地创建一个包含任意对象的容器。
std::vector<std::any> v; // requires C++17
但是该容器的用户必须知道哪个索引包含什么类型:
if (v[0].type() == typeid(ArbitraryUserType)) {
const auto& item = std::any_cast<ArbitraryUserType>(v[0]);
// work on item ...
}
由于类型的编译时性质,您作为库编写器无法执行该any_cast
。必须在用户的源代码中说明。
通常,不要试图将Python的思维模式塞入C ++ 。它永远不会完结,尤其是当您尝试规避C ++最基本的基础之一:其强大的静态类型系统时。
注意:
boost::any
。std::vector<std::variant<Type1, Type2, etc>>
是一个很好的选择。使用any
,用户完全有责任跟踪其类型。因为所有类型检查都在运行时发生,所以编译器无法提供帮助。另一方面,Variant
带来了大量的编译时安全性。还有boost::variant
作为非C ++ 17的替代方案。基本上,您正在尝试序列化(编码)和反序列化(解码)任意类型。没有这些类型的合作,这是不可能的。
您的方法仅适用于可以一点一点复制的琐碎类型。 C ++甚至具有以下类型特征:std::is_trivially_copyable。最后,您支持这些基础类型和C样式结构,但仅此而已。
想象一下,您的T
函数的encode()
是std::string
。只需放置一个std::string
包含一个指向单独分配的内存的指针,该内存就会存储实际的字符串数据。字符串对象本身只是该指针的管理包装。 encode()
仅序列化包装对象,而不对具有实际数据的指向的存储块进行序列化。
即使在反序列化期间您可以从位流中实例化任意类型,该流也不完整。您需要实现的是Python copy.deepcopy
的C ++版本,没有每种类型的合作就不可能实现。看看C ++序列化库-以Cereal作为简单示例-看看这种合作在实践中如何看待。