采用何种工具来查看型别推导结果,取决于你在软件开发过程的哪个阶段需要该信息。主要研究三个可能的阶段:撰写代码阶段、编译阶段、运行时阶段。
IDE编译器
IDE中的代码编译器通常会在你将鼠标指针选停止某个程序实体,如变量、形参、函数等时,显示出该实体的型别。例如以下这段代码:
const int theAnswer = 42; auto x = theAnswer; auto y = &theAnswer;
IDE编译器很可能会显示出,x的型别推导结果是int,而y则是const int*。
而让这种方法奏效,代码就多多少少要处于一种可编译状态。因为让IDE提供此类信息的工作原理是让C++编译器(或至少也是其前端)在IDE内执行一轮。如果该编译器不能在分析你的代码时得到足够的有用信息,自然也就无法显示出推导除了何种型别。
对于像int这样的平凡型别,从IDE能得到的信息大体良好。不过你很快就会看到,一旦较为复杂的型别现身,IDE显示的信息就不太有用了。
编译器诊断信息
想要让编译器显示其推导出的型别,一条有效的途径是使用该型别推导某些编译错误。而报告错误的消息几乎肯定会提及导致该错误的型别。
运行时输出
Boost的TypeIndex库(常写作Boost.TypeIndex),虽说该库不是C++的一部分,但IDE和像TD这样的模板也不是。Boost库(可从boost.com获得)的好处还不止于此,他跨平台、开源。这样一来,Boost库和那些依赖标准库的代码有几乎同样的可移植性。
下面介绍一下函数f是如何在使用Boost.TypeIndex的条件下产生精确的型别信息的:
#include <boost/type_index.hpp> template<typename T> void f(const T& param) { using std::cout; using boost::typeindex::type_id_with_cvr; //显示T的型别 cout << "T = " << type_id_with_cvr<T>().pretty_name() << ' '; //显示param的型别 cout << "param = " << type_id_with_cvr<decltype(param)>().pretty_name() << ' '; .... }
这种方法的工作原理是函数模板boost::typeindex::type_id_with_cvr接受一个型别实参(我们想要获取信息的型别),而且不会移除const、volatile和引用饰词(这也是改模板的名字中为什么含有with_cvr字样),该函数模板返回一个boost::typeindex::type_index对象,它利用成员函数pretty_name产生一个包含人类可读的型别表示的std::string。
std::vector<Widget> createVec(); //工厂函数 const auto vw = createVec(); //使用工厂函数返回值初始化vw if(!vw.empty()) { f(&vw[0]); //调用f ... }
在使用GNU和Clang编译器的情况下,Boost.TypeIndex产生了以下的(精准)输出:
T = Widget const* param = Widget const* const&
微软编译器取得的结果本质上完全相同:
T = class Widget const* param = class Widget const* const&
请记住无论是IDE编译器、编译器错误消息,还是像Boost.TypeIndex这样的库都仅仅是你弄明白你的编译器推导所得型别的辅助工具。他们都十分有用,但是说到底,理解条款1~条款3的型别推导知识这一点无可替代。
要点速记:
1、利用IDE编译器,编译器错误消息、和Boost.TypeIndex库常常能够查看到推导而得的型别。
2、有些工具产生的结果可能会无用,或者不准确。所以,理解C++型别推导规则是必要的。