到现在为止,C++ 仍然是计算机编程领域的经典语言之一,C++ 17 标准在2017上半年已经探讨确定。本期我们汇集了编程专家——祁宇(《深入应用 C++ 11》作者,C++ 开源社区 purecpp.org 创始人)的多年心得小结,并具体介绍了 C++ 17 最新标准中值得开发者关注的新特点和基本用法。

文/祁宇

本文将借助分析 magic _ get 源码来介绍 magic _ get 实现的关键科技,深入剖析实现 pod 类型反射的机理。

反射是一种根据元数据来获得类外部信息的模式,通过元数据就可以获得对象的字段和技巧等信息。C# 和 Java 的反射模式都是通过获得对象的元数据来推动的。反射可以用于依赖注入、ORM 对象-实体映射、序列化和反序列化等与对象原本信息密切相关的领域。比如 Java 的 Spring 框架,其依赖注入的基础是构建在反射的基础之上的,可以按照元数据获取类型的信息并动态建立对象。ORM 对象-实体之间的映射也是借助反射实现的。Java 和 C# 都是基于前面运行时的语言,中间运行时提供了反射模式,所以反射针对运行时语言来说很容易,但是针对没有中间运行时的语言,要想实现反射是很困难的。

在2016年的 CppCon 技术大会上,Antony Polukhin 做了一个关于 C++ 反射的发言vc6.0怎么写c语言,他强调了一个实现反射的新思路,即无需使用宏、标记和额外的软件就能推动反射。看起来似乎是一件不也许完成的任务,因为 C++ 是没有反射模式的,无法直接获得对象的元信息。但是 Antony Polukhin 发现对 pod 类型使用 Modern C++ 的模板元方法可以实现这种的编译期反射。他开源了一个 pod 类型的编译期反射库 magic _ get(),这个库也打算开启 boost。我们来看看 magic _ get 的使用示例。

#include struct foo { int some_integer; char c;};foo f {777, '!'};auto& r1 = boost::pfr::flat_get<0>(f); //通过索引来访问对象foo的第1个字段auto& r2 = boost::pfr::flat_get<1>(f); //通过索引来访问对象foo的第2个字段

通过这个例子可以发现,magic _ get 确实实现了非侵入式访问 foo 对象的数组,不需要写任何宏、额外的代码或者专门的软件,直接在编译期就可以访问 pod 对象的数组,没有运行期负担,确实有点 magic。

本文将借助分析 magic _ get 源码来介绍 magic _ get 实现的关键科技,深入剖析实现 pod 类型反射的机理。

实现 pod 类型反射的模式是这么的:先将 pod 类型转化为对应的 tuple 类型,接下来将 pod 类型的值赋给 tuple,然后就可以通过索引去访问 tuple 中的元素了。所以推动 pod 反射的关键就是如何将 pod 类型转化为对应的 tuple 类型和 pod 值数组给 tuple。

pod 类型对应的 tuple 类型是什么样的呢?以下面的 foo 为例,foo 对应的 tuple 应该是 tuple,即 tuple 中的元素种类和排序和 pod 类型中的数组完全一一对应。

根据结构体生成一个 tuple 的基本模式是,按次序将结构体中每个数组的类别萃取出来并储存起来,后面再取下来生成对应的 tuple 类型。然而字段的类别是不同的,C++ 也没有一个能直接保存不同类型的容器vc6.0怎么写c语言,因此必须一个变通的方式,用一个间接的方式来储存萃取出来的字段类别,即将类型转化为一个 size _ t 类型的 id,将这个 id 保存到一个 array 中,后面根据这个 id 来获得实际的 type 并生成对应的 tuple 类型。

这里应该解决的一个问题是怎样推动类型和 id 的互相转换。

先通过一个空的模板类用来存放实际的类别,再通过 C++ 14 的 constexpr 特性,在编译期返回某个类别对应的编译期 id,就可以实现 type 转换为 id 了。具体代码如下:

https://ipad-cms.csdn.net/cms/article/code/3445

上面的代码在编译期将类别 int 和 char 做了一个编码,将类别转换为一个具体的编译期常量,后面就可以按照这种编译期常量来获得对应的详细类型。

编译期根据 id 获取 type 的代码如下:

constexpr auto id_to_type( std::integral_constant<:size_t> ) noexcept { int res{}; return res; }constexpr auto id_to_type( std::integral_constant<:size_t> ) noexcept { char res{}; return res; }

上面的代码中 id _ to _ type 返回的是 id 对应的类别的示例,如果要获得 id 对应的类别还必须借助 decltype 推导出来。magic _ get 通过一个宏将 pod 基本类别都做了一个编码,以推动 type 和 id 在编译期的互相转换。

#define REGISTER_TYPE(Type, Index) \ constexpr std::size_t type_to_id(identity) noexcept { return Index; } \ constexpr auto id_to_type( std::integral_constant<:size_t index=""> ) noexcept { Type res{}; return res; } \// Register all base types here REGISTER_TYPE(unsigned short , 1) REGISTER_TYPE(unsigned int , 2) REGISTER_TYPE(unsigned long long , 3) REGISTER_TYPE(signed char , 4) REGISTER_TYPE(short , 5) REGISTER_TYPE(int , 6) REGISTER_TYPE(long long , 7) REGISTER_TYPE(unsigned char , 8) REGISTER_TYPE(char , 9) REGISTER_TYPE(wchar_t , 10) REGISTER_TYPE(long , 11) REGISTER_TYPE(unsigned long , 12) REGISTER_TYPE(void* , 13) REGISTER_TYPE(const void* , 14) REGISTER_TYPE(char16_t , 15) REGISTER_TYPE(char32_t , 16) REGISTER_TYPE(float , 17) REGISTER_TYPE(double , 18) REGISTER_TYPE(long double , 19)

将类别编码以后,保存在那里或者怎么取下来是接着要缓解的难题。magic _ get 通过定义一个 array 来保存结构体字段类别 id。

template struct array { typedef T type; T data[N]; static constexpr std::size_t size() noexcept { return N; } };

array 中的定长数组 data 中保存数组类型对应的 id,数组下标就是字段在结构体中的位置索引。

前面介绍了怎样实现字段类别的保存和获得,那么这个字段类别是怎样从 pod 结构体中萃取出来的呢?具体的做法分为三步:

下面是详细实现代码:

template constexpr auto fields_count_and_type_ids_with_zeros() noexcept { static_assert(std::is_trivial::value, "Not applyable"); array<:size_t sizeof> types{}; detect_fields_count_and_type_ids(types.data, std::make_index_sequence{}); return types;}template constexpr auto array_of_type_ids() noexcept { constexpr auto types = fields_count_and_type_ids_with_zeros(); constexpr std::size_t count = count_nonzeros(types); array<:size_t count=""> res{}; for (std::size_t i = 0; i < count; ++i) { res.data[i] = types.data[i]; } return res; }

定义 array 时必须定义一个固定的变量长度,长度为多少适合呢?应按结构体最多的字段数来确认。因为结构体的数组数最多为 sizeof(T),所以 array 的长度设置为 sizeof(T)。array 中的元素全部初始化为0。一般情况下,结构体字段数通常不会超过 array 的厚度,那么 array 中就经常出现多余的元素,所以还必须将 array 中多余的数组移除,只储存有效的泛型类别 id。具体的做法是计算出 array 中非零的元素有多少,接着再把非零的元素赋给一个新的 array。下面是推导 array 非零元素个数,同样是通过 constexpr 实现编译期计算。

本文来自电脑杂谈,转载请注明本文网址:

http://www.pc-fly.com/a/jisuanjixue/article-129594-1.html

C语言的VC开发环境界面介绍,【c语言在vc++6.0中编写界面程序】相关推荐

  1. 【应用笔记】【AN001】VC#开发环境下基于以太网的4-20mA电流采集(基于modbus tcp 协议)...

    版本:第一版 作者:毛鹏 杨帅 日期:20151108 简介 4-20mA电流环具有广泛的应用前景,在许多行业中都发挥着重要作用.本文主要介绍了以太网接口的4-20mA电流采集模块在VC#环境下进行温 ...

  2. C语言核心技术-C语言概述与开发环境搭建

    C语言概述 C语言发展简史 起源 1972年,贝尔实验室的Dennis Ritchie和Ken Thompson在开发Unix操作系统时设计了C语言,该操作系统的90%以上的代码都是由C语言实现,后期 ...

  3. linux swift开发环境,Linux平台swift语言开发学习环境搭建

    摘要 介绍在Ubuntu平台搭建Swift开发环境: 介绍Swift脚本解析器swift的使用: 介绍Swift编译器swiftc的使用: 1.序言 这两天一直忙,没来得及记录东西,周三12月4日凌晨 ...

  4. 我的全栈之路-C语言基础之C语言概述与开发环境搭建

    我的全栈之路-C语言基础之C语言概述与开发环境搭建 我的全栈之路 1.1 信息技术发展趋势 1.2 浅谈计算机系统架构 1.2.1 计算机系统架构概述 1.2.2 计算机硬件系统 1.2.2 计算机软 ...

  5. Python学习笔记 - Python语言概述和开发环境

    一.Python简介 1.1  Python语言简史 Python由荷兰人吉多·范罗苏姆(Guido van Rossum)于1989年圣诞节期间,在阿姆斯特丹,为了打发圣诞节的无聊时间,决心开发一门 ...

  6. RStudio v1.2.1335 发布,R 语言的集成开发环境

    开发四年只会写业务代码,分布式高并发都不会还做程序员? >>>   RStudio 是 R 语言的集成开发环境,分为面向桌面用户 IDE 和 Linux R 服务器版编辑器两种编辑器 ...

  7. Windows Phone 8开发环境搭建介绍

    1. 如果是Windows 8系统中安装VS2012,可以直接安装: Windows Phone SDK 8.0 是一个功能齐全的开发环境,可用于构建 Windows Phone 8.0 和 Wind ...

  8. DL之IDE:深度学习之计算机视觉开发环境搭建的详细流程(Ubuntu16.04+cuda9.0+cuDNN7.4.2+tensorflow_gpu)

    DL之IDE:深度学习之计算机视觉开发环境搭建的详细流程(Ubuntu16.04+cuda9.0+cuDNN7.4.2+tensorflow_gpu) 目录 1.安装nvidia驱动 2.安装CUDA ...

  9. 大型医院云HIS系统:采用前后端分离架构,前端由Angular语言、JavaScript开发;后端使用Java语言开发 融合B/S版电子病历系统

    一套医院云his系统源码 采用前后端分离架构,前端由Angular语言.JavaScript开发:后端使用Java语言开发.融合B/S版电子病历系统,支持电子病历四级,HIS与电子病历系统均拥有自主知 ...

最新文章

  1. 3年国奖、一作9篇SCI,完美逆袭的中大博士坦言自己也曾濒临挂科
  2. Sql PATINDEX 函数
  3. 如何用asp.net实现校验功能!
  4. java Annotation 简单理解
  5. IIS Form 认证 保护HTML页面
  6. t-SNE(t-distributed stochastic neighbor embedding)
  7. 阿里云AIoT全新工业和农业云端一体机深度产品,全链路数据化实现效率提升
  8. navicat如何连接腾讯mysql_使用Navicat连接腾讯云Mysql数据库
  9. java 23种设计模式(转载)
  10. [转载]C# WinForm开发系列 - 文章索引
  11. ai音响怎么连接网络_KTV音响设备怎么连接?点歌机怎么连接?学习下
  12. 从《网管员必读》系列丛书获奖看读者的真正需求——成功原因分析(一)
  13. c++ qt5范例开发大全_237页建设工程监理内业资料全套范例,附百份案例表格,快拿走...
  14. EEGLAB及其插件下载安装
  15. 浅析VO、DTO、DO、PO的概念、区别和用处
  16. 40163 php,【PHP】微信支付JsApi 40163错误,_PHP_ 少侠科技
  17. Cadence OrCad Capture新建工程的方法
  18. WEB端和手机端-三种提示框架
  19. 图像处理之高斯金字塔
  20. matlab海杂波统计建模及CFAR阈值分割

热门文章

  1. JAVA语言异常,Java语言中的异常
  2. 88是python语言的整数类型_Python基础数据类型题
  3. vb 导出整数 科学计数法_可整数组的计数
  4. Java 中接口和抽象类竟然有 7 点不同?
  5. Spring Cloud Alibaba 深度解密!
  6. 一道题决定去留:为什么synchronized无法禁止指令重排,却能保证有序性?
  7. vb.net axWindowsMediaPlayer 控件使用
  8. okhttp_utils的使用以及与服务端springboot交互中遇到的问题
  9. 在Windows10上安装WSL使用binwalk命令
  10. 复习----使用链表实现栈(后进先出)及迭代