当前位置: 首页 > news >正文

html5国内网站建设django做企业级网站

html5国内网站建设,django做企业级网站,微信社群运营工具,ps做游戏下载网站有哪些内容前序文章请看#xff1a; C模板元编程详细教程#xff08;之一#xff09; C模板元编程详细教程#xff08;之二#xff09; C模板元编程详细教程#xff08;之三#xff09; C模板元编程详细教程#xff08;之四#xff09; C模板元编程详细教程#xff08;之五 C模板元编程详细教程之一 C模板元编程详细教程之二 C模板元编程详细教程之三 C模板元编程详细教程之四 C模板元编程详细教程之五 C模板元编程详细教程之六 C模板元编程详细教程之七 C模板元编程详细教程之八 多选一结构 这一章我们来看看如何编写一个多选一的结构STL中提供了std::variant我们就来实现一个简易版。注意下面我们实现的variant与STL中的是有区别的但大体思路是相同的请读者不要以本节的代码参考使用std::variant。 我们的诉求是创建一个数据结构「可能」存放多种类型但同一时间只能有一种并且可以在运行期变化为另一种。这里比较容易想到的做法就是用共合体类型存储数据再加一个用于表示当前哪种数据是生效的index。请看代码 template typename T1, typename T2 class variant { public:// 针对每种情况的构造variant(const T1 t1);variant(const T2 t2); private:union {T1 t1;T2 t2;} data;int index; // 当前生效的数据序号 };只不过这样我们很快就会发现很多严重的问题 对于任意个数的参数无法映射到union结构中如果数据类型不含无参构造函数union结构的构造会报错variant的构造函数依赖数据类型的拷贝构造对于不可拷贝类型来说无法创建。 因此我们必须换一个思路。既然一开始我们想到用union主要也是为了内存空间的复用所以我们只需要自己来维护一片数据空间就好了以参数类型中长度最大的为准创建一个缓存空间即可。 template typename... Types class variant {private:void *data std::malloc(std::max(sizeof(Types)...)); // 计算出最长的Typeint index; // 当前生效的数据序号 };接下来的任务就是构造函数。由于这里的Types是变参所以无法穷举与此同时我们希望可以就地构造跳过「拷贝构造」这个阶段以支持不可拷贝类型的数据因此必须有一个Index来标识后面跟变参 template typename... Types class variant {public:template size_t Index, typename... Argsvariant(Args ... args); // 大概是这个意思private: void *data std::malloc(std::max(sizeof(Types)...)); // 计算出最长的Typeint index; // 当前生效的数据序号 };然而出于语法限制构造函数用模板生成的话是无法手动实例化的例如 variant1, int va; // 1, int会识别为类型的模板参数而不是构造函数的模板参数因此构造函数的模板参数只能依赖于自动推导所以我们就需要提供一个工具用来「传递」这个Index。 template size_t Index struct in_place_index_t {}; // 单纯的静态工具用于传递Index没有运行期意义template size_t Index constexpr inline in_place_index_tIndex in_place_index; // 对应in_place_index_t类型的实例template typename... Types class variant {public:template size_t Index, typename... Argsvariant(const in_place_index_tIndex , Args ... args);private:void *data std::malloc(std::max(sizeof(Types)...)); int index; };然后构造时也同样通过in_place_index来构造传递这个Index // 用于测试的类型 struct Test1 {Test1(int, double); }; struct Test2 {Test1(char, int); };void Demo() {variantTest1, Test2 var{in_place_index0, 1, 1.5}; // 用于构造Test1类型variantTest1, Test2 var{in_place_index1, A, 1}; // 用于构造Test2类型 }那么接下来的问题就是如何解析了variant本身的参数是一组typename列表但构造传进来的是一个Index序号如何对应呢相信读者到现在应该已经建立初步的感觉了没错递归大法好 template size_t Index, typename Head, typename... Args struct get_type_by_index : get_type_by_indexIndex - 1, Args... {};template typename Head, typename... Args struct get_type_by_index0, Head, Args... {using type Head; };// 验证Demo void Demo() {std::cout std::is_same_vtypename get_type_by_index2, int, double, char, void *::type , char std::endl; // 1 }有了这个工具我们就可以从类型列表里通过Index取出对应的类型了以此来完成variant的构造函数 // 实现构造函数 template typename... Types template size_t Index, typename... Args variantTypes...::variant(const in_place_index_tIndex , Args ... args): index(Index) {// 先把需要构造的类型拿出来using data_type typename get_type_by_indexIndex, Args...::type;// 在data处进行就地构造new(data) std::decay_tdata_type(std::forwardArgs(args)...); }最难的构造已经完成了我们先实现一下周边功能析构、拷贝构造和赋值函数先放一放给出一个阶段性的代码 template size_t Index struct in_place_index_t {}; // 单纯的静态工具用于传递Index没有运行期意义template size_t Index constexpr inline in_place_index_tIndex in_place_index; // 对应in_place_index_t类型的实例template size_t Index, typename Head, typename... Args struct get_type_by_index : get_type_by_indexIndex - 1, Args... {};template typename Head, typename... Args struct get_type_by_index0, Head, Args... {using type Head; };template typename... Types class variant {public:template size_t Index, typename... Argsvariant(const in_place_index_tIndex , Args ... args);// 获取当前序号int index() const;// 取出数据template size_t Indexauto get() const - std::add_lvalue_reference_tstd::decay_ttypename get_type_by_indexIndex, Types...::type;private:void *data_ std::malloc(std::max(sizeof(Types)...)); // 计算出最长的Typeint index_; // 当前生效的数据序号 };// 实现构造函数 template typename... Types template size_t Index, typename... Args variantTypes...::variant(const in_place_index_tIndex , Args ... args): index_(Index) {// 先把需要构造的类型拿出来using data_type typename get_type_by_indexIndex, Args...::type;// 在data处进行就地构造new(data_) std::decay_tdata_type(std::forwardArgs(args)...); }// 获取序号 template typename... Types int variantTypes...::index() const {return index_; }// 取出数据这个功能在std::variant中其实实现在std::get中 template typename... Types template size_t Index auto variantTypes...::get() const - std::add_lvalue_reference_tstd::decay_ttypename get_type_by_indexIndex, Types...::type {using data_type std::decay_ttypename get_type_by_indexIndex, Types...::type;return *static_castdata_type *(data_); }接下来我们要攻克的就是析构、拷贝构造、拷贝赋值这几个问题了它们的难点在于没有静态的Index参数可供使用但还要找到现在数据的类型。就拿析构来说析构函数并没有静态的Index参数只有一个运行时的index成员但我们要找到此时index_成员表示的data_所指向数据的实际类型然后调用这个类型的析构函数。拷贝构造、拷贝赋值也同样需要先析构现有数据所以面临同样的问题。 这种情况怎么办呢类比前面章节介绍的元组的动态get方法我们这里也采取「静态穷举生成所有可能情况代码」的方法。 以析构为例在析构时要根据index_去判断当前保存的数据是哪一种类型的然后去调用对应类型的析构函数。因此我们需要在静态期就提供每一种类型的析构方法然后将它们和类型的Index关联起来这样在运行时就可以调用了。 template typename... Types class variant {public:// 无关代码暂时省略 ~variant(); // 析构函数private:void *data_ std::malloc(std::max(sizeof(Types)...));int index_; // 当前生效的数据序号// 生成每一个Type下对应类型的析构方法template typename Typevoid destory_data(); };template typename... Types template typename Type void variantTypes...::destory_data() {// 用data_指针按照对应的类型调用析构函数static_caststd::add_pointer_tType(data_)-~Type(); }// 实现析构函数 template typename... Types variantTypes...::~variant() {// 析构函数中把所有的index对应的destory_data保存下来编译期完成这样一个映射表std::arrayvoid (variantTypes...::*)(), sizeof...(Types) destory_functions {variantTypes...::destory_dataTypes... // 按照类型参数展开把对应的destory_data实例的函数指针保存下来};// 到了运行期根据当前实际的index_值选择对应的析构方法if (data_ ! nullptr) {(this-*destory_functions.at(index_))();std::free(data_);} }对于拷贝构造、拷贝赋值来说首先把原来的内容析构调然后再根据被复制方的index_来调用对应的构造函数。于是我们还需要补充一个index_与构造函数的映射表思路和析构完全相同 template typename... Types class variant {public:// 无关代码先省略variant(const variant va);private:void *data_ std::malloc(std::max(sizeof(Types)...));int index_; // 当前生效的数据序号// 生成每一个Type下对应类型的析构方法template typename Typevoid destory_data();// 生成每一个Type下对应类型的构造方法// 注意由于我们要把生成的所有方法保存在数组中因此函数类型需要一致所以参数用泛型指针template typename Typevoid create_data(const void *obj); };template typename... Types template typename Type void variantTypes...::create_data(const void *obj) {// 用data_指针按照对应的类型调用拷贝构造new(data_) Type(*static_castconst Type *(obj)); }template typename... Types variantTypes...::variant(const variant va): index_(va.index_) {// 静态期保存所有类型的构造函数std::arrayvoid (variantTypes...::*)(const void *), sizeof...(Types) create_functions {variantTypes...::create_dataTypes...};// 动态时根据index_调用对应的构造(this-*create_functions.at(index_))(va.data_); }有了这样的思路那么我们就可以完善所有的代码了拷贝赋值函数可以按照相同的方法写出来了只不过需要先析构再重新构造。下面给出整个项目的完整代码 // 辅助工具 template size_t Index struct in_place_index_t {}; // 单纯的静态工具用于传递Index没有运行期意义template size_t Index constexpr inline in_place_index_tIndex in_place_index; // 对应in_place_index_t类型的实例template size_t Index, typename Head, typename... Args struct get_type_by_index : get_type_by_indexIndex - 1, Args... {};template typename Head, typename... Args struct get_type_by_index0, Head, Args... {using type Head; };// variant结构的声明 template typename... Types class variant {public:template size_t Index, typename... Argsvariant(const in_place_index_tIndex , Args ... args);variant(const variant va);variant(variant va);~variant();variant operator (const variant va);variant operator (variant va);// 获取当前序号int index() const;// 取出数据template size_t Indexauto get() const - std::add_lvalue_reference_tstd::decay_ttypename get_type_by_indexIndex, Types...::type;private:void *data_ std::malloc(std::max(sizeof(Types)...));int index_; // 当前生效的数据序号// 生成每一个Type下对应类型的析构方法template typename Typevoid destory_data();// 生成每一个Type下对应类型的构造方法template typename Typevoid create_data(const void *obj); };// 实现构造函数 template typename... Types template size_t Index, typename... Args variantTypes...::variant(const in_place_index_tIndex , Args ... args): index_(Index) {using data_type typename get_type_by_indexIndex, Args...::type;new(data_) std::decay_tdata_type(std::forwardArgs(args)...); }// 实现析构函数 template typename... Types variantTypes...::~variant() {// 析构函数中把所有的index对应的destory_data保存下来编译期完成这样一个映射表std::arrayvoid (variant::* const)(), sizeof...(Types) destory_functions {variant::destory_dataTypes...};// 到了运行期根据当前实际的index_值选择对应的析构方法if (data_ ! nullptr) {(this-*destory_functions.at(index_))();std::free(data_);} }// 实现拷贝构造函数 template typename... Types variantTypes...::variant(const variant va): index_(va.index_) {// 静态期保存所有类型的构造函数std::arrayvoid (variantTypes...::*)(const void *), sizeof...(Types) create_functions {variantTypes...::create_dataTypes...};// 动态时根据index_调用对应的构造(this-*create_functions.at(index_))(va.data_); }// 实现拷贝赋值函数 template typename... Types variantTypes... variantTypes...::operator (const variant va) {// 先析构现有数据std::arrayvoid (variantTypes...::*)(), sizeof...(Types) destory_functions {variantTypes...::destory_dataTypes...};(this-*destory_functions.at(index_))();// 再重新构造std::arrayvoid (variantTypes...::*)(const void *), sizeof...(Types) create_functions {variantTypes...::create_dataTypes...};(this-*create_functions.at(index_))(va.data_);return *this; }// 实现移动构造函数 template typename... Types variantTypes...::variant(variant va): index_(va.index_), data_(va.index_) {// 上面直接浅拷贝即可然后把被移动的data_置空va.data_ nullptr;va.index_ -1; // 标记为不合法值 }// 实现移动赋值函数 template typename... Types variantTypes... variantTypes...::operator (variant va) {// 先析构现有数据std::arrayvoid (variantTypes...::*)(), sizeof...(Types) destory_functions {variantTypes...::destory_dataTypes...};(this-*destory_functions.at(index_))();// 再浅拷贝data_ va.data_;index_ va.index_;// 把被移动的data_置空va.data_ nullptr;va.index_ -1; // 标记为不合法值return *this; }// 私有方法的实现 template typename... Types template typename Type void variantTypes...::create_data(const void *obj) {// 用data_指针按照对应的类型调用拷贝构造new(data_) Type(*static_castconst Type *(obj)); }template typename... Types template typename Type void variantTypes...::destory_data() {// 用data_指针按照对应的类型调用析构函数static_caststd::add_pointer_tType(data_)-~Type(); }// 公有方法的实现 // 获取序号 template typename... Types int variantTypes...::index() const {return index_; }// 取出数据这个功能在std::variant中其实实现在std::get中 template typename... Types template size_t Index auto variantTypes...::get() const - std::add_lvalue_reference_tstd::decay_ttypename get_type_by_indexIndex, Types...::type {using data_type std::decay_ttypename get_type_by_indexIndex, Types...::type;return *static_castdata_type *(data_); }小结 这一篇以一个「多选一」结构为例带大家体验了一下模板元编程的实际使用方式当然这还没完下一篇我们会针对这个多选一结构写一个「成员访问器」会用到更多模板元编程的技巧。
http://www.hkea.cn/news/14259131/

相关文章:

  • 海南住房城乡建设网站湖北做网站系统哪家好
  • 网站建设推广有没有wordpress代码增强插件
  • 网站建设的渠道策略网页游戏代理加盟
  • j网站开发安徽网站建设详细教程
  • 广安发展建设集团门户网站网新中英企业网站管理系统
  • 怎么设置网站镇江网站建设制作公司
  • 学校网站建设目的是什么好的平面设计
  • 网站开发部门工资入什么科目茌平做创建网站公司
  • 酒业网站建设怎么做网站在网上能搜到你
  • 网站建设功能需求文档网站被挂黑链怎么删除
  • 做单页购物网站用什么好哈尔滨制作网站工作室
  • 免费建立网站的有哪里做网站的无锡
  • 网站自助建站开发制作凡科网做的网站
  • 做电影资讯网站算侵权吗网站备案 ip
  • 推广网站加盟北京网站设计引流微信hyhyk1
  • 网站正在建设中的苏州360推广 网站建设
  • 网站注册界面东莞制作公司网站
  • 网站制作员益阳学校网站建设
  • 上海做公司网站多少钱网页制作软件frontpage2000属于
  • 姑苏区住房和建设局网站重庆刚刚发布
  • 网站在百度的图标显示不正常显示宜春市城市建设网站
  • 贷款超市网站开发中山网站开发
  • 提供网站建设费用哈尔滨建设银行招聘信息网
  • 建设网站公司选哪家好营销外包团队
  • 企业网站开发技术题库那些做环保网站的好
  • 建设工程平台网站深圳软件定制
  • 滨海住房和城乡建设局网站做网站美工排版
  • soho需要建网站吗WordPress下级
  • 详细论述制作网站的步骤商城模板建站
  • 郑州网站seo推广网站建设公司郑州