Effective Modern C++ Item 4 掌握查看型别推导结果的方法

对于我们需要查看型别推导结果的时候,主要分为三个阶段:写代码阶段,编译阶段,运行时阶段。

IDE编辑器

IDE编辑器基本上都具有在鼠标悬停在变量或者auto 等字段上会自动推导类型的功能。如下代码所示:

const int theAnswer = 42;
auto x = theAnswer;
auto y = &theAnswer;

IDE编辑器会显示出,x的型别推导结果是int,y的是 const int &。

编译器诊断信息

一种另辟蹊径的方式,是故意诱发一个错误,然后让报错提示出型别信息。常用的手法如下代码:

template<typename T>    //只声明TD而不定义
class TD;               //TD是"型别显示类"的缩写(Type Display)

有了这个工具,只要试图具象化该模板,就会诱发一个错误,从而达到让编译器告知型别推导结果的作用,示例如下:

TD<decltype(x)> xType;  //诱发包括x和y的型别错误信息
TD<decltype(y)> yType;

这段代码编译的时候,会报告如下问题:

error: aggregate “TD< int > xType” has incomplete type and cannot be defined
error: aggregate “TD< const int *> yType” has incomplete type and cannot be defined

运行时输出

C++提供了这样的方式,可以输出某个变量的类型。

std::cout << typeid(x).name() << std::endl;
std::cout << typeid(y).name() << std::endl;

但这种方式有一个弊端,输出的字符不是那么好理解,并且每家编译器的格式都不一样,源于C++委员会并未强制定义需要输出什么样的格式。具体不好理解的字符就不展示了,大家有兴趣可以自己尝试,这里只讲要点

看下面一个例子:

template<typename T>
void f(const T& param)
{
    using std::cout;
    cout << "T = " << typeid(T).name() << '\n';             //这里GNU和Clang,VS都会显示出Widget const *的型别输出
    cout << "param = " << typeid(param).name() << '\n';     //这里GNU和Clang,VS都会显示出Widget const *的型别输出
}

std::vector<Widget> createVec();
const auto vw = createVec();
if (!vw.empty()) {
     f(&vw[0]);
     ...
}

这样的输出看似一致,但实际上却是错误的。回忆一下之前的模板型别推导,在模板f中,param被声明称型别const T&。那么如果T是int,param的型别应该就是const int&才对。

很不幸的是,std::type_info::name并不可靠,更加可怕的是,这种不正确的输出结果是符合标准的。

而且更加不幸的是,IDE显示的型别信息也并不可靠。还是上面那份代码,某IDE把T显示为:

const std::_Simple_types< std::_Wrap_alloc< std::_Vec_base_types< Widget, std::allocator< Widget>>::_Alloc>::value_type>::value_type *

param的型别显示成这样:

const std::_Simple_types<…>::value_type *const &

显然冗长的T类型不易理解,param的型别虽然很短,但是有让人困惑的 ...存在,其实...就是T的类型的意思。

那么,std::type_info不好用,IDE也不好用,到底有什么好用的呢,其实是有的——Boost的TypeIndex库
Boost.TypeIndex不仅仅是跨平台的,开源的,并且不受编译器解析限制的稳定。上述代码例子用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;

    cout << "T = " << type_id_with_cvr<T>.pretty_name() << '\n';
    cout << "param = " << type_id_with_cvr<decltype(param)>.pretty_name() << '\n';
}

std::vector<Widget> createVec();
const auto vw = createVec();
if (!vw.empty()) {
     f(&vw[0]);
     ...
}

这时,无论GNU,Clang,还是VS,均会输出

T = Widget const *
param = Widget const* const &

无论IDE,编译器错误消息,还是Boost.TypeIndex库,都只是理解型别推导的辅助工具。他们十分有用,但还是需要写代码者自己对Item1 ~ Item3有深入理解的前提下。

要点速记
1. 利用IDE编辑器,编译器错误消息,Boost.TypeIndex库常常能够辅助获得型别推导结果。
2. 上述工具有时候并不完全正确,自身能理解C++型别推导是非常重要的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值