检察自动类型推导效果的方法

王柳  金牌会员 | 2024-5-17 05:37:09 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 896|帖子 896|积分 2688

《深入分析C++的auto自动类型推导》《深入分析decltype和decltype(auto)》两篇文章中先容了使用auto和decltype以及decltype和auto结合来自动推导类型的推导规则和用法,虽然确定类型的事情交给编译器去做了,但是在有的时间我们可能还是想知道编译器推导出来的类型具体是什么,下面就来先容几种获取类型推导效果的方法,根据开发的差别阶段,你可以在差别阶段采用差别的方法,好比在编写代码时,编译代码时,代码运行时。
使用IDE检察

当你在编写代码的过程中想检察一下某个变量推导出来的类型是什么,做到胸有定见,其实在IDE中就可以直接检察,如今的IDE都比较智能,如微软的Visual Studio和目前比较流行的跨平台编辑器VS Code都有此功能。你只要将鼠标移到想要检察的那个变量上面,就会弹出这个变量的类型,不过要让IDE可以或许推导出代码中变量的类型,你的代码至少要没有语法错误,因为IDE会静态分析你代码来推导出这些类型,如下面的代码:
  1. int a;
  2. auto x = a;
  3. auto& y = a;
复制代码
你把鼠标移动x上面,则会弹出表现“int x”,把鼠标移动y上面,就会弹出表现“int& y”。对于C++的内置类型,IDE基本上都能推导出来,但是遇到比较复杂的类型或者复杂的代码上下文中,IDE可能就有点不敷智能了。
借助工具检察

当IDE不能正确表现出变量的类型的时间还可以选择借助外部的工具来检察,这里推荐一个在线工具,地点是:https://cppinsights.io,这是一个基于Clang的工具,对用户所写的C++代码转换成最终情势的C++代码,有点类似于C/C++的预处置惩罚器一样,把一些宏代码替换成真实的代码一样,但它的功能更进一步也更强大,该工具支持基于范围的循环、结构化绑定、生成默认构造函数、初始化列表、auto与decltype转换成真实类型,最强大的是会生成模板实例化后的代码,这些功能对于调试C++代码非常有用。使用的界面如下:

(点击检察大图)
左边是我们输入的原始代码,输入结束之后点击左上角的三角形按钮,就会生成右边经过转换后的代码,可以看到右边中已经将类型别名T1到T10等的类型转换成具体的类型了,使用时可以在上面的下拉列表框中选择差别的C++标准。
需要留意的是,这个工具我发现了一个Bug,就是上面代码中的T9类型别名,正确的类型应该是func函数的类型:int(int, int),这里表现为它的返回值的类型了。
编译时打印

编译器肯定是知道变量的类型的,但是它没法直接告诉你,有一个可以让编译器告诉你的办法,就是编译发生错误时编译器在陈诉的错误信息中肯定会提到导致此错误的类型,因此我们可以声明一个如下的模板:
  1. template<typename T>
  2. class dumpType;
复制代码
因为上面的模板只有声明,没有具体的定义,因此假如要实例化这个模板就会导致一个编译错误。以是我们想要检察哪个变量的类型,只要将这个变量的类型作为模板的形参去实例化它,就会导致一个错误,在编译器给出的错误信息里就会表现出这个变量的具体类型,如下所示:
  1. const int x1 = 1;
  2. auto j = x1;
  3. dumpType<decltype(j)>{};
复制代码
编译时发生错误,其中输出的错误信息含有这一行:
  1. error: implicit instantiation of undefined template 'dumpType<int>'
复制代码
dumpType中尖括号内的int就是j的类型了,以此类推,只要将想要检察的变量替换到上面的参数中就可以了。但是这里有一个缺点,就是每次只能检察一个变量的类型,需要检察多个变量时就显得繁琐。幸亏C++11标准引入了支持可变参数的模板特性,我们可以使用这个特性来美满上面的功能,将上面的模板修改一下:
  1. template<typename T>
  2. class dumpType;
复制代码
如今可以一次传递多个参数给此模板,如下面的例子:
  1. template<typename T>
  2. class dumpType;int func(int, int) {    int x;    return x;}class Base {public:    int x = 0;};int main() {    const Base b;    const int ci = 1;    auto x = ci;    using T1 = decltype(x);    using T2 = decltype((x));    using T3 = decltype(b.x);    using T4 = decltype((b.x));    using T5 = decltype(func);    dumpType{};}
复制代码
编译时将输出以下的错误信息:
  1. error: implicit instantiation of undefined template 'dumpType<int>'
复制代码
运行时输出

有时我们想要在代码运行的时间输出某些变量的类型,这时间可以借助C++的RTTI特性,C++标准库提供了typeid函数和type_info类,对变量或者类型调用typeid会返回一个type_info对象,type_info类里有一个成员函数name,这个函数返回一个const char*类型的名称,但这个名称一样平常都经过C++的混淆,比较不易看懂,如以下的代码:
  1. auto add (auto p1, auto p2) { return p1 + p2; };
  2. auto d = add(1, 2.0);
  3. printf("type of d is %s\n", typeid(d).name());
  4. auto s = add("hello"s, "world"s);
  5. printf("type of s is %s\n", typeid(s).name());
复制代码
输出的效果是:
  1. type of d is d
  2. type of s is NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
复制代码
输出效果中的d代表的是double类型,如int类型的话则表现i,std::string类型的原型比较复杂,以是输出来的效果比较难看懂。但这种方法最大的缺点是功能不太美满,好比对于引用类型它无法正确的表现出来,好比下面的代码:
  1. int i = 1;
  2. auto& j = i;
  3. printf("type of j is %s\n", typeid(j).name());
复制代码
变量j正确的类型应该是int&,但是上面的输出效果是i,是int类型,估计是j作为参数传给typeid函数的时间是作为值传递的,丢失了引用属性,在这里CV修饰词也会被忽略掉,如在上面定义变量j时加上const修饰,但输出效果还是int类型。
这时可以采用另外一种手段来输出变量的类型,跟上末节中的例子一样借助模板的技术,实现一个模板函数,在模板函数中使用编译器提供的宏,把这个函数的原型打印出来,函数原型中就包罗了函数的参数个数及其类型,这个宏由于不是C++标准中定义的,是由各编译器扩展的,因此名称不一样,在GCC/Clang中是__PRETTY_FUNCTION__,在微软的MSVC中是__FUNCSIG__,如下代码:
[code]#include templatevoid dumpType() {    // GCC/Clang使用这行    std::cout

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表