Item 4: 知道如何查看推导类型

知道如何查看推导类型

目前版本是英文,难以理解的地方(针对我自己)也用中文进行了解释,20210117之前会把英文转换成中文, 大家应该看得懂的。

Three posiibilities to get type deduction information:

  • when codes edition
  • during compilation
  • at runtime

IDE Editors

Code editors in IDEs often show the types of program entities (e.g., variables, parameters, functions, etc.) when you do something like hover your cursor over the entity. For example, given this code,

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

what makes it possible for the IDE to offer this kind of information is a C++ compiler (or at least the front end of one) running inside the IDE.
For simple types like int, information from IDEs is generally fine. As we’ll see soon, however, when more complicated types are involved, the information displayed by IDEs may not be particularly helpful.

Compiler Diagnostics

An effective way to get a compiler to show a type it has deduced is to use that type in a way that leads to compilation problems. The error message reporting the problem is virtually sure to mention the type that’s causing it.

#include 
#include 
using namespace std;

template 
class TD;

int main()
{
    const int theAnswer = 42;
    auto x = theAnswer;
    auto y = &theAnswer;

    TD xtype;
    TD xtype1;

    TD ytype;
    TD ytype1;

    return 0;
}

// VS2019 MSVC编译的时候会产生以下错误:
// 错误 C2079 “xtype”使用未定义的 class“TD”
// 错误 C2079 “xtype1”使用未定义的 class“TD”
// 错误 C2079 “ytype”使用未定义的 class“TD” 
// 错误 C2079 “ytype1”使用未定义的 class“TD

Runtime Output

use typeid and std::type_info::name to create a textual repsentation of the type suitable for display.

std::cout<

Calls to std::type_info::name are not guaranteedd to return anything sensible. consider a more complex example:

template                 
// template function to
void f(const T& param);              
// be called

std::vector createVec(); 
// factory function

const auto vw = createVec();         
// init vw w/factory return

if (!vw.empty()) {
  f(&vw[0]);                         
  // call f
  …
  // 实际的 T 和 param的类型是什么呢?这里做个解释:
  // 首先,得了解两个名词:
  // 1. 指针 const 常量的指针(point-to-const)
  // 2. const 指针, 指针不可修改
        /* eg.
         int a = 17;
         int b = 18;
         const int* p = &a; // 这里 p是指向const 常量的指针
         *p = 19; // 报错,表达式必须为可修改的左值
         p = &b; // 可以

         int* const p1 = &a; // const 指针
         p1 = &b; // 报错,表达式必须为可修改的左值
        */
  // 3. 模板函数 f(const T& param)中, const是用来修饰 T 的,即 T 的值不可以修改,
  //    当 T 类型为int时,param 的类型为 const int&, 
  //    当 T 类型为 char* 时,要说明指针的值不可修改,要换个格式,param的类型为 char* const
  // 4. 关于参数 &vw[0] 的理解如下:
        /* 
          vm 的类型为 const std::vector
          所以,vm 的元素值不可以修改,元素的地址也不可以修改。
          所以&vm[0]的类型为 const Widget* const, 即,指向const常量的const指针
         */
}

template
void f(const T& param)
{
  using std::cout;

  cout << "T =     " << typeid(T).name() << '\n';     // show T

  cout << "param = " << typeid(param).name() << '\n'; // show param's type
  …                                                   
}  


// the specification for std::type_info::name mandates that the type be treated as if it had been passed to a template function as a by-value parameter.
// As Item 1 explains, that means that if the type is a reference, its reference-ness is ignored, 
// and if the type after reference removal is const (or volatile), its constness (or volatileness) is also ignored. // That’s why param’s type—which is const Widget * const &—is reported as const Widget*. 
// First the type’s reference-ness is removed, and then the constness of the resulting pointer is eliminated.
// 此段代码为上述代码的完整版,可以直接拷贝至VS中运行
#include 
#include 

template
void f(const T & param)
{
    using std::cout;

    cout << "T =     " << typeid(T).name() << '\n';     // show T

    cout << "param = " << typeid(param).name() << '\n'; // show param's type
}

class Widget {

};

std::vector createVec() {

    std::vector wgts;
    wgts.push_back(Widget());
    return wgts;
}

int main()
{
    const auto vw = createVec();

    if (!vw.empty()) {
        f(&vw[0]);
       
    }
    return 0;
}

// 输出结果为:
// T =     class Widget const *
// param = class Widget const *

// 输出的类型不是我们想要的,解释参考上面

The Boost TypeIndex library(Boost.TypeIndex) is designed to succeed.
这里简单介绍一下boost库,boost库与C++ STL标准库关联甚广,STL 库很多都是参考/基于Boost库而来。目前,我在看公司里韩国前辈的代码,发现代码中boost库使用很多,所以最近,我也在学习boost库,主要是 boost.asio 方面,我也在上作了相关的笔记,大家可以参考参考...
需要boost库的在评论处留下邮箱,稍后会发送给你,目前本人使用的boost_1_73_0, 官网最新的是boost_1_75_0.

// 使用 Boost.TypeIndex 来 得出 精确的类型信息
#include 

template
void f(const T& param)
{
  using std::cout;
  using boost::typeindex::type_id_with_cvr;

  // show T
  cout << "T =     "
       << type_id_with_cvr().pretty_name()
       << '\n';

  // show param's type
  cout << "param = "
       << type_id_with_cvr().pretty_name()
       << '\n';
}
// 输出结果:
// T =     class Widget const *
// param = class Widget const * const &

// The function template boost::typeindex::type_id_with_cvr takes a type argument (the type about which we want information) 
// and doesn’t remove const, volatile, or reference qualifiers (hence the “with_cvr” in the template name). 

总结

  • 通常可以使用IDE编辑器,编译器错误消息和Boost TypeIndex库查看推导的类型。

  • 某些工具的得出的结果可能并不精确,也不具有指导价值,因此对C ++的类型推导规则的理解仍然至关重要。

你可能感兴趣的:(Item 4: 知道如何查看推导类型)