如何获取C++中auto和decltype类型推导的结果

在《深入解析C++的auto自动类型推导》和《深入解析decltype和decltype(auto)》两篇文章中介绍了使用auto和decltype以及decltype和auto结合来自动推导类型的推导规则和用法。尽管确定类型的事情交给编译器去做了,但有时候我们可能还是想知道编译器推导出来的类型具体是什么。下面将介绍几种获取类型推导结果的方法,根据开发的不同阶段,你可以在不同阶段采用不同的方法,比如在编写代码时,编译代码时,代码运行时。

利用IDE查看

当你在编写代码的过程中想查看某个变量推导出来的类型,可以在IDE中直接查看。现在的IDE都比较智能,如微软的Visual Studio和目前比较流行的跨平台编辑器VS Code都有此功能。将鼠标移到想要查看的变量上面,就会弹出这个变量的类型。对于C++的内置类型,IDE基本上都能推导出来,但是遇到比较复杂的类型或者复杂的代码上下文中,IDE可能就有点不够智能了。

借助工具查看

当IDE不能正确显示出变量的类型的时候还可以选择借助外部的工具来查看,这里推荐一个在线工具,地址是: https://cppinsights.io 。这是一个基于Clang的工具,对用户所写的C++代码转换成最终形式的C++代码,支持基于范围的循环、结构化绑定、生成默认构造函数、初始化列表、auto与decltype转换成真实类型,最强大的是会生成模板实例化后的代码,这些功能对于调试C++代码非常有用。

(点击查看大图)

左边是我们输入的原始代码,输入结束之后点击左上角的三角形按钮,就会生成右边经过转换后的代码,可以看到右边中已经将类型别名T1到T10等的类型转换成具体的类型了,使用时可以在上面的下拉列表框中选择不同的C++标准。

需要注意的是,这个工具我发现了一个Bug,就是上面代码中的T9类型别名,正确的类型应该是func函数的类型:int(int, int),这里显示为它的返回值的类型了。

编译时打印

编译器肯定是知道变量的类型的,但是它没法直接告诉你,有一个可以让编译器告诉你的办法,就是编译发生错误时编译器在报告的错误信息中肯定会提到导致此错误的类型。因此我们可以声明一个如下的模板:

template<typename T>
class dumpType;

因为上面的模板只有声明,没有具体的定义,所以如果要实例化这个模板就会导致一个编译错误。所以我们想要查看哪个变量的类型,只要将这个变量的类型作为模板的形参去实例化它,就会导致一个错误,在编译器给出的错误信息里就会显示出这个变量的具体类型。

运行时输出

有时我们想要在代码运行的时候输出某些变量的类型,这时候可以借助C++的RTTI特性,C++标准库提供了typeid函数和type_info类,对变量或者类型调用typeid会返回一个type_info对象,type_info类里有一个成员函数name,这个函数返回一个const char*类型的名称。但这个名称一般都经过C++的混淆,比较不易看懂。

auto add (auto p1, auto p2) { return p1 + p2; };
auto d = add(1, 2.0);
printf("type of d is %s\n", typeid(d).name());
auto s = add("hello"s, "world"s);
printf("type of s is %s\n", typeid(s).name());

输出结果中的d代表的是double类型,如int类型的话则显示i,std::string类型的原型比较复杂,所以输出来的结果比较难看懂。但这种方法最大的缺点是功能不太完善,比如对于引用类型它无法正确的显示出来。

这时可以采用另外一种手段来输出变量的类型,跟上小节中的例子一样借助模板的技术,实现一个模板函数,在模板函数中利用编译器提供的宏,把这个函数的原型打印出来,函数原型中就包含了函数的参数个数及其类型,这个宏由于不是C++标准中定义的,是由各编译器扩展的,因此名称不一样。

此篇文章同步发布于我的微信公众号:查看自动类型推导结果的方法

如果您感兴趣这方面的内容,请在微信上搜索公众号iShare爱分享或者微信号iTechShare并关注,或者扫描以下二维码关注,以便在内容更新时直接向您推送。

标签:游戏攻略