C++实现类似python中list, dict的结构
前言
公司某段业务需要将python代码移植到c++, 其中多数情况下, 只需简单的更改词法和语法即可, 直到我遇到如下场景:
-
初始化时使用大量数据, 且会做多次数据拼接. 有时数据中还会混入不同的类型
在python中, 这一需求可使用
list轻松地实现, 但c++中就xx了.. -
大量使用dict, 且value中的数据类型不统一.
这些情况下, 如果不做些封装处理, 代码将变得非常难看. 经过查阅资料, 发现boost库中有一个类非常适合这种场景:boost::any, 遂开干.
实现
首先需要安装
boost,我使用vcpkg安装的, 亦可直接到[官网][https://www.boost.org/0]下载, 参考https://zhuanlan.zhihu.com/p/235157113
-
安装
vcpkggit clone https://github.com/microsoft/vcpkg vcpkg\bootstrap-vcpkg.bat vcpkg\vcpkg integrate install -
安装
boost(比较慢,须耐心等待)vcpkg\vcpkg install boost -
实现
Elem.hpp#pragma once #include#include #include #include #include using namespace std; using boost::any; union ListElement { unsigned char byte; unsigned short word; unsigned int dword; unsigned long long qword; float f; double d; }; class Elem { public: Elem() = default; template Elem(const ValueType& value) { this->data = value; } Elem(const Elem& other) { this->data = other.data; } bool operator==(bool value) { return ((bool)toByte()) == value; } bool operator==(char value) { return toByte() == value; } bool operator==(unsigned char value) { return toByte() == value; } bool operator==(short value) { return toInt16() == value; } bool operator==(unsigned short value) { return toInt16() == value; } bool operator==(int value) { return toInt32() == value; } bool operator==(unsigned int value) { return toInt32() == value; } Elem operator=(const Elem& e) { this->data = e.data; return this->data; } /*static Elem operator+(const Elem& left ,const Elem& right) { if (left.type() == typeid(int)) return this->data + e.toInt32(); }*/ unsigned char toByte() { ListElement e = this->convert(); return e.byte; } short toInt16() { ListElement e = this->convert(); return e.word; } int toInt32() { ListElement e = this->convert(); return e.dword; } long long toInt64() { ListElement e = this->convert(); return e.qword; } float toFloat() { ListElement e = this->convert(); return e.f; } double toDouble() { ListElement e = this->convert(); return e.d; } string toString() { if (this->isType ()) return "\""+this->cast ()+ "\""; else if (this->isType ()) return "\""+string(this->cast ())+ "\""; else if (this->isType ()) return "\""+string(this->cast ())+"\""; else if (this->isType ()) return this->cast () ? "true" : "false"; else if (this->isType () || this->isType ()) return to_string(this->toByte()); else if (this->isType () || this->isType ()) return to_string(this->toInt16()); else if (this->isType () || this->isType ()) return to_string(this->toInt32()); else if (this->isType () || this->isType ()) return to_string(this->toInt32()); else if (this->isType () || this->isType ()) return to_string(this->toInt64()); else if (this->isType ()) return to_string(this->toFloat()); else if (this->isType ()) return to_string(this->toDouble()); else return string("undefined"); } template T cast() { if (this->data.type() != typeid(T)) throw exception(("data type:"+string(this->data.type().name())+" is not "+string(typeid(T).name())).c_str()); T result = boost::any_cast (this->data); return result; } const boost::typeindex::type_info& type() { return this->data.type(); } template bool isType() { if (this->empty()) return false; return this->data.type() == typeid(T); } bool empty() { return this->data.empty(); } private: ListElement convert() { ListElement e{ 0 }; if (this->data.type() == typeid(unsigned char)) e.byte = boost::any_cast (this->data); else if (this->data.type() == typeid(char)) e.byte = boost::any_cast (this->data); else if (this->data.type() == typeid(short)) e.word = boost::any_cast (this->data); else if (this->data.type() == typeid(unsigned short)) e.word = boost::any_cast (this->data); else if (this->data.type() == typeid(int)) e.dword = boost::any_cast (this->data); else if (this->data.type() == typeid(unsigned int)) e.dword = boost::any_cast (this->data); else if (this->data.type() == typeid(long)) e.dword = boost::any_cast (this->data); else if (this->data.type() == typeid(unsigned long)) e.dword = boost::any_cast (this->data); else if (this->data.type() == typeid(long long)) e.qword = boost::any_cast (this->data); else if (this->data.type() == typeid(unsigned long long)) e.qword = boost::any_cast (this->data); else if (this->data.type() == typeid(float)) e.f = boost::any_cast (this->data); else if (this->data.type() == typeid(double)) e.d = boost::any_cast (this->data); else { string name = this->data.type().name(); throw std::exception(("data type " + name + " is not supported").c_str()); } return e; } private: any data; }; -
实现
List.hpp#pragma once #include#include #include #include "Elem.hpp" using namespace std; class List { public: List() = default; List(const List& list, bool isRestruct = true) { if (isRestruct) { for (int i = 0; i < list.data.size(); i++) { this->data.push_back(list.data[i]); } return; } this->data.push_back(list); } List(const string& str) { for (int i = 0; i < str.size(); i++) { this->data.push_back((unsigned char)str[i]); } } /* 其实现必须在头文件,否则会找不到符号 */ template List(Arg... args) { append(args...); } template void append(T value) { data.push_back(value); } template void append(Head head, Rail... last) { data.push_back(head); append(last...); } List operator+(const int i) { this->data.push_back(i); return this; } List operator+(const List& list) { List tempList; for (int i = 0; i < this->data.size(); i++) { tempList.data.push_back(this->data[i]); } for (int i = 0; i < list.data.size(); i++) { tempList.data.push_back(list.data[i]); } return tempList; } List operator=(const List& list) { this->data.clear(); for (int i = 0; i < list.data.size(); i++) { this->data.push_back(list.data[i]); } return this; } List operator+=(const string& str) { for (int i = 0; i < str.size(); i++) { this->data.push_back(str[i]); } return this; } List operator+=(const List& list) { for (int i = 0; i < list.data.size(); i++) { this->data.push_back(list.data[i]); } return this; } List operator+=(unsigned char c) { this->data.push_back(c); return this; } Elem& operator[](int index) { return data[index]; } void set(int index, Elem a) { this->data[index] = a; } Elem get(int index) { return this->data[index]; } void foreach(void(*callback)(Elem&)) { for (int i = 0; i < this->data.size(); i++) { callback(this->data[i]); } } string toByteString() { string str; for (int i = 0; i < this->data.size(); i++) { str += this->data[i].toByte(); } if (str.size() != this->data.size()) throw exception(("List to string failed,"+to_string(this->data.size() - str.size())+" byte(s) are missing").c_str()); return str; } int size() { return this->data.size(); } bool empty() { return this->data.size() == 0; } bool exist(int index) { if (this->data.size() >= index && !this->data[index].empty()) { return true; } return false; } static void fromJson(string jsonValue) { } string toIntArray() { string intArray; for (auto i = 0; i < this->data.size() - 1; i++) { intArray += to_string((unsigned int)data[i].toByte()) + ", "; } intArray += to_string((unsigned int)data[this->data.size() - 1].toByte()); return intArray; } string toStringArray() { string array = "["; for (auto i = 0; i < this->data.size(); i++) { array += data[i].toString()+ (i==(this->data.size()-1)? "":","); } array += "]"; return array; } private: vector data; }; -
实现
Dict.hpp#pragma once #include#include #include -
测试案例
// cppTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include#include #include 效果: