網(wǎng)站制作二級(jí)網(wǎng)頁怎么做網(wǎng)絡(luò)推廣預(yù)算方案
本文簡單的記錄一下采用模板來實(shí)現(xiàn)序列化與反序列的思路, 同時(shí)采用C++20標(biāo)準(zhǔn)的concept和requires來簡化模板函數(shù)的選擇。
首先了解一下自定義類支持序列化的兩種方式:
一、序列化自定義類型(侵入式)
struct Test {std::string name;int age;//序列化接口template<class Archive>void serialize(Archive & ar) const {ar & REFLEX(name);ar & REFLEX(age);}
};
二、序列化自定義類型(非侵入式)
struct Test2 {std::string name;int age;
};//序列化接口
template<class Archive>
void serialize(Archive & ar,const Test2& t) {ar & REFLEX(t.name);ar & REFLEX(t.age);
}
這種方法用于序列化一些外部庫定義的類,或一些不希望修改實(shí)現(xiàn)的類。
接下來實(shí)現(xiàn)一個(gè)采用二進(jìn)制方案的序列化類
//用于識(shí)別自定義類內(nèi)部是否支持serialize函數(shù)
template<typename AR, typename V>
concept is_user_def_inside = requires(AR ar, V v) {v.serialize(ar);
};//用于識(shí)別自定義類外部是否支持了serialize函數(shù)
template<typename AR, typename V>
concept is_user_def_outside = requires(AR ar, V v) {serialize(ar, v);
};class ArchiveOut {
public:ArchiveOut(std::ostream& os):m_os(os){}using ArchiveTp = ArchiveValue;template<typename T>ArchiveOut& operator & (const T& val){this->operator<<(val);return *this;}//自定義類(侵入式)template<typename T>requires(is_user_def_inside<ArchiveOut,T>)ArchiveOut& operator << (const T& val){val.serialize(*this);return *this;}// 可平凡復(fù)制 template<typename T>requires(std::is_trivially_copyable<T>::value)ArchiveOut& operator << (const T& val){m_os.write((const char *)&val, sizeof(T));return *this;}//自定義類(非侵入式)template<typename T>requires(!std::is_trivially_copyable<T>::value && !is_user_def_inside<ArchiveOut,T> && is_user_def_outside<ArchiveOut,T>)ArchiveOut& operator << (const T& val){serialize(*this, val);return *this;}//string 特化ArchiveOut& operator << (const std::string& val){size_t size = val.size();m_os.write((const char *)&size, sizeof(size));m_os.write((const char *)val.data(), size * sizeof(typename std::string::value_type));return *this;}//其它類型處理
private:std::ostream& m_os;
};
前文中的REFLEX為自定義宏, 用于生成諸如json、xml時(shí),對(duì)字段名的反射, 因?yàn)榛诙M(jìn)制序列化的時(shí)候,可以只保存值,而不需要保存字段名,但生成json、xml等格式時(shí)需要用到字段名稱,因此實(shí)現(xiàn)Reflex時(shí),需要根據(jù)序列化類型字段選擇。
#define REFLEX(param) CReflex(param, #param)
#define REFLEX_ALIAS(param, alias) CReflex(param, alias)//只針對(duì)值進(jìn)行序列化
enum class ArchiveValue {
};
//對(duì)字段名和值進(jìn)行序列化
enum class ArchiveKeyValue {
};template<typename T>
concept is_key_value = requires() {std::is_same<typename T::ArchiveTp, ArchiveKeyValue>::value;
};template<typename T>
concept is_only_value = requires() {std::is_same<typename T::ArchiveTp, ArchiveValue>::value;
};template<typename T>
class CReflex {
public:CReflex(T& value, const std::string& strName) :m_value(value), m_name(strName) {};template<typename Archive>requires(is_only_value<Archive>)void serialize(Archive& ar)const {ar & m_value;}template<typename Archive>requires(!is_only_value<Archive> && is_key_value<Archive>)void serialize(Archive& ar)const {ar & (m_name, m_value);}
private:T& m_value;std::string m_name;
};
到這里一個(gè)大致的模型已經(jīng)實(shí)現(xiàn),當(dāng)然,真正實(shí)施起來還有許多細(xì)節(jié)需要補(bǔ)充。
附完整代碼:
#include <string>
#include <concepts>
#include <iostream>
#include <sstream>
#include <type_traits>#define REFLEX(param) CReflex(param, #param)
#define REFLEX_ALIAS(param, alias) CReflex(param, alias)//只針對(duì)值進(jìn)行序列化
enum class ArchiveValue {
};
//對(duì)字段名和值進(jìn)行序列化
enum class ArchiveKeyValue {
};template<typename T>
concept is_key_value = requires() {std::is_same<typename T::ArchiveTp, ArchiveKeyValue>::value;
};template<typename T>
concept is_only_value = requires() {std::is_same<typename T::ArchiveTp, ArchiveValue>::value;
};template<typename T>
class CReflex {
public:CReflex(T& value, const std::string& strName) :m_value(value), m_name(strName) {};template<typename Archive>requires(is_only_value<Archive>)void serialize(Archive& ar)const {ar & m_value;}template<typename Archive>requires(!is_only_value<Archive> && is_key_value<Archive>)void serialize(Archive& ar)const {ar & (m_name, m_value);}
private:T& m_value;std::string m_name;
};template<typename T>
concept is_container = requires(T res, T::value_type v) {res.insert(res.begin(), v);
};template<typename AR, typename V>
concept is_user_def_inside = requires(AR ar, V v) {v.serialize(ar);
};template<typename AR, typename V>
concept is_user_def_outside = requires(AR ar, V v) {serialize(ar, v);
};class ArchiveOut {
public:ArchiveOut(std::ostream& os):m_os(os){}using ArchiveTp = ArchiveValue;template<typename T>ArchiveOut& operator & (const T& val){this->operator<<(val);return *this;}//自定義類(侵入式)template<typename T>requires(is_user_def_inside<ArchiveOut,T>)ArchiveOut& operator << (const T& val){val.serialize(*this);return *this;}// 可平凡復(fù)制 template<typename T>requires(std::is_trivially_copyable<T>::value)ArchiveOut& operator << (const T& val){m_os.write((const char *)&val, sizeof(T));return *this;}//自定義類(非侵入式)template<typename T>requires(!std::is_trivially_copyable<T>::value && !is_user_def_inside<ArchiveOut,T> && is_user_def_outside<ArchiveOut,T>)ArchiveOut& operator << (const T& val){serialize(*this, val);return *this;}//string 特化ArchiveOut& operator << (const std::string& val){size_t size = val.size();m_os.write((const char *)&size, sizeof(size));m_os.write((const char *)val.data(), size * sizeof(typename std::string::value_type));return *this;}//其它類型處理
private:std::ostream& m_os;
};struct Test {std::string name;int age;//序列化接口template<class Archive>void serialize(Archive & ar) const {ar & REFLEX(name);ar & REFLEX(age);}
};struct Test2 {std::string name;int age;
};//序列化接口
template<class Archive>
void serialize(Archive & ar,const Test2& t) {ar & REFLEX(t.name);ar & REFLEX(t.age);
}int main()
{Test t = {"zhangshan", 36};Test2 t2 = {"liubei", 38};std::ostringstream ss;ArchiveOut ar(ss);ar << t << t2;std::cout << "size : " << ss.str().length() << ", value: " << ss.str() << std::endl;return 0;
}