首页 > 编程语言 >类型推导--Effective modern C++ 学习笔记

类型推导--Effective modern C++ 学习笔记

时间:2022-09-22 11:56:39浏览次数:97  
标签:const 推导 Effective -- modern param int 引用 类型

类型推导--Effective modern C++ 学习笔记

auto和template虽然用起来很爽,但是作为程序员我们应该了解C++编译器做了哪些事情,从而确实的保证整套机制能够顺利的运作。

1.模板类型推导

    //模板声明部分
    template<typename T>
    void f(ParamType param);
    //调用部分
    f(expr)

模板类型推导就是关于如何根据expr的类型来推断出T的类型以及ParamType的类型。通常来讲,T和ParamType不会一样,因为ParamType往往会给T加上const或者引用之类的修饰。比如T可能是String类型,但ParamType是const String&类型,这在平常的函数模板使用中是非常常见的一种情况。

但是即便刨除T和ParamType之间的类型不同,我们也需要知道这样一个事情,虽然T的类型推导应该完全依赖于expr的类型,但是实际上并非如此。T的类型推导不仅仅依赖于expr的类型,也取决于ParamType的类型。

具体来看的话,ParamType造成的影响可以分为三类来进行讨论。

  1. ParamType是一个指针或引用,但不是通用引用(Universal Reference)
  2. ParamType一个通用引用
  3. ParamType既不是指针也不是引用

1.1 当ParamType是一个指针或引用,但不是通用引用

    //模板声明部分
    template<typename T>
    void f(T& param);
    //变量声明
    int x=27;                       //x是int
    const int cx=x;                 //cx是const int
    const int& rx=x;                //rx是指向作为const int的x的引用
    //调用部分
    f(x);                           //T是int,param的类型是int&
    f(cx);                          //T是const int,param的类型是const int&
    f(rx);                          //T是const int,param的类型是const int&

这里面注意观察的其实就是f(cx)和f(rx),即便传入参数类型是一个引用,T也并不会被推导为引用类型,这是因为在类型推导中,对象的引用性(reference-ness)会被忽略。不过从另一方面我们也可以看到常量性(constness)是没有被忽略的,传入一个const型的对象,T也会带有const。

同时如果更改一下这个ParamType的类型声明,我们可以看到一些不同的结果。

    //模板声明部分
    template<typename T>
    void f(const T& param);
    //变量声明
    int x=27;                       //x是int
    const int cx=x;                 //cx是const int
    const int& rx=x;                //rx是指向作为const int的x的引用
    //调用部分
    f(x);                           //T是int,param的类型是const int&
    f(cx);                          //T是int,param的类型是const int&
    f(rx);                          //T是int,param的类型是const int&

如果我们将const属性声明在了函数参数的形参中,那么T将不会保留常量性。

1.2 ParamType一个通用引用

首先对于那些不太了解通用引用的人(Universal Reference),我推荐Scott Meyers也就是本书作者在isocpp.org上的一篇博客,这里面详细讨论了什么是通用引用或者说万能引用。同时通用引用的符号容易让你以为这里的声明是右值引用,但其实两者完全不同。

    //模板声明部分
    template<typename T>
    void f(T&& param);              //param现在是一个通用引用类型
    //变量声明
    int x=27;                       //x是int
    const int cx=x;                 //cx是const int
    const int& rx=x;                //rx是指向作为const int的x的引用
    //调用部分
    f(x);                           //x是左值,所以T是int&,
                                    //param类型也是int&

    f(cx);                          //cx是左值,所以T是const int&,
                                    //param类型也是const int&

    f(rx);                          //rx是左值,所以T是const int&,
                                    //param类型也是const int&

    f(27);                          //27是右值,所以T是int,
                                    //param类型就是int&&

这里可以看到对于通用引用的类型推导规则是与常规引用完全不同的,当param被声明为通用引用时,T也会带上引用性。也就是说当通用引用被使用时,类型推导会区分左值实参和右值实参,但是对非通用引用时不会区分。

1.3 ParamType既不是指针也不是引用

这种情况即是我们的函数进行按值传递的时候,也就是每次都会拷贝我们所传进来的实参。

    //模板声明部分
    template<typename T>
    void f(T param);
    //变量声明
    int x=27;                       //x是int
    const int cx=x;                 //cx是const int
    const int& rx=x;                //rx是指向作为const int的x的引用
    //调用部分
    f(x);                           //T和param的类型都是int
    f(cx);                          //T和param的类型都是int
    f(rx);                          //T和param的类型都是int

在这种情况下,T和param都会完全忽略传进来的实参的引用性和常量性,因为拷贝出来的对象的特性已经完全不受原来实参的影响了。

2.auto的类型推导

auto的类型推导其实与模板类型中T的推导大同小异,并且只在一个情况下会出现不同的推导。那就是当我们使用统一初始化(uniform initialization)时。

    auto x1 = 27;                   //类型是int,值是27
    auto x2(27);                    //同上
    auto x3 = { 27 };               //类型是std::initializer_list<int>,
                                    //值是{ 27 }
    auto x4{ 27 };                  //同上

在上述的情形下,auto都可以像常见模板中的T那样被推导出来类型,但以下会出现一种情况,auto可以被推导出来,但是在模板中无法推导出来。

    auto x = { 11, 23, 9 };         //x的类型是std::initializer_list<int>
    template<typename T>            //带有与x的声明等价的
    void f(T param);                //形参声明的模板

    f({ 11, 23, 9 });               //错误!不能推导出T

这是因为auto类型推导假定花括号表示std::initializer_list而模板类型推导并不会这么做。 并且还有一点值得注意,C++14中auto可以被用在函数的返回值以及lambda的形参说明中,但是auto在这里所使用的推导规则是模板类型推导。

3. 引用

Effective Modern C++ 翻译

标签:const,推导,Effective,--,modern,param,int,引用,类型
From: https://www.cnblogs.com/halftheworldaway/p/16718733.html

相关文章

  • CSS3渐变
    简介CSS3渐变(gradients)可以让你在两个或多个指定的颜色之间显示平稳的过渡。以前,你必须使用图像来实现这些效果。但是,通过使用CSS3渐变(gradients),你可以减少下载的时间......
  • redis分布式锁,redis中set和setnx的区别
    转自:https://www.zhangshilong.cn/work/320344.html Redis命令SETNX的使用(包含Java分布式锁实现)可以参考Redis官网对SETNX命令的介绍:https://redis.io/commands/setnx......
  • ES6对Function函数类型升级优化
    ES6对Function函数类型升级优化优化部分箭头函数(核心)箭头函数内的this指向的是函数定义时所在的对象,而不是函数执行时所在的对象。ES6中函数里的this总是指向函数执行......
  • 实验2:Open vSwitch虚拟交换机实践
    实验2:OpenvSwitch虚拟交换机实践一、实验目的能够对OpenvSwitch进行基本操作;能够通过命令行终端使用OVS命令操作OpenvSwitch交换机,管理流表;能够通过Mininet的Pytho......
  • 软件开发人员的 5 个次要/被动收入理念
    软件开发人员的5个次要/被动收入理念PhotobyPixabay这些天来,似乎每个人都在寻找赚更多钱的方法,自Covid来袭以来,被动收入和次要收入已成为热门话题。这对于寻找收......
  • ByteArrayOutputStream用法---读写类型数据
    ByteArrayOutputStream用法 字节数组流:ByteArrayOutputStream:  可以捕获内存缓冲区的数据,转换成字节数组。ByteArrayoutputStreambout=newByteArrayOutputStr......
  • switch 实时渲染问题
    从数据库查询出数据,其中状态值使用(0、1)表示,此时switch不能实时的渲染。解决方法:在active-value和inactive-value前面加上:<el-table-columnlabel="状态"alig......
  • Mysql的explain详解
    使用mysql提供的explain命令来查询sql语句的执行计划,查看sql语句有没有使用上索引,有没有全表扫描等。expain出来的信息有12列,分别是,id,select_type,table,partitions,type,possi......
  • MBR30300VCT-ASEMI肖特基MBR30300VCT二极管
    编辑:llMBR30300VCT-ASEMI肖特基MBR30300VCT二极管型号:MBR30300VCT品牌:ASEMI封装:TO-220AB特性:肖特基二极管正向电流:30A反向耐压:300V恢复时间:50~100ns引脚数量:3芯......
  • React + Eartho 与 3 个简单的步骤集成
    React+Eartho与3个简单的步骤集成如果您已经关注并访问了您的第一个地球和React经验,那么我相信你会感觉很棒。它一次为开发人员提供了许多好处。如果你有地球......