4.2 auto类型推导

一、动静态类型

静态类型:使用前需要声明和定义。

动态类型:无需声明直接使用(需要定义)。如Python、Perl、JavaScript

本质区别在于类型检查时机,静态在编译期,动态在运行时(依赖类型推导)

C++11引入了两种类型推导:auto和decltype。两者都是静态类型,因此必须是编译期推导的类型。

而且auto声明必须定义,否则无法推导。实际上auto不是类型,只是类型占位符,在编译期推导成功后进行类型替换。

二、auto优势

简化代码
#include <string>
#include <vector>
void loopover(std::vector<std::string> & vs) {std::vector<std::string>::iterator i = vs.begin(); // 想要使用iterator,往往需要书写大量代码for (; i < vs.end(); i++) {// 一些代码}
}
#include <string>
#include <vector>
void loopover(std::vector<std::string> & vs) {for (auto i = vs.begin(); i < vs.end(); i++) {// 一些代码}
}

对比上述两例代码可以看到使用auto,能够简化代码类型。

避免声明出错,尤其是有隐式转换的操作时
class PI {
public:
double operator* (float v) {return (double)val * v;     // 这里精度被扩展了
}
const float val = 3.1415927f;
};
int main() {float radius = 1.7e10;PI pi;auto circumference = 2 * (pi * radius);
}

上述代码radius未float类型,而在经过计算之后得到的circumference精度得到了扩展(double),而有时我们容易依赖原有类型将circumference声明为float类型,这就使得计算结果精度降低了。

而使用auto则会自动推导为double类型。

但是,对于计算溢出的场景,自动推导并不能扩展其类型(因为只能对类型结果推导,而不能对计算结果推导)

#include <iostream>
using namespace std;
int main() {unsigned int a = 4294967295;     //最大的unsigned int值unsigned int b = 1;auto c = a + b;           // c的类型依然是unsigned intcout << "a = " << a << endl;     // a = 4294967295cout << "b = " << b << endl;     // b = 1cout << "a + b = " << c << endl;// a + b = 0return 0;
}

上述仍然会将c推导为unsigned int类型,而非更大存储范围的unsigned long。

自适应性在模板上的支持
template<typename T1, typename T2>
double Sum(T1 & t1, T2 & t2) {auto s = t1 + t2;    // s的类型会在模板实例化时被推导出来return s;
}
int main() {int a = 3;long b = 5;float c = 1.0f, d = 2.3f;auto e = Sum<int ,long>(a, b);       // s的类型被推导为longauto f = Sum<float,float>(c, d);     // s的类型被推导为float
}
// 编译选项:g++ -std=c++11 4-2-7.cpp

可以自动推导多个输入类型参数计算后的结果类型。当然这里来看仍然需要要求为double类型(因为返回值为double),但是实际上结合后面的decltype可以实现追踪返回类型,从而将返回类型也实现自动推导。

宏上的使用
#define Max1(a, b) ((a) > (b)) ? (a) : (b)
#define Max2(a, b) ({ \
auto _a = (a); \
auto _b = (b); \
(_a > _b) ? _a: _b; })
int main() {int m1 = Max1(1*2*3*4, 5+6+7+8);int m2 = Max2(1*2*3*4, 5+6+7+8);
}

我们定义了两种类型的宏Max1和Max2。两者作用相同,都是求a和b中较大者并返回。前者采用传统的三元运算符表达式,这可能会带来一定的性能问题。因为a或者b在三元运算符中都出现了两次,那么无论是取a还是取b,其中之一都会被运算两次。而在Max2中,我们将a和b都先算出来,再使用三元运算符进行比较,就不会存在这样的问题了

三、auto使用细则

不继承&
int x;
int * y = &x;
double foo();
int & bar();
auto * a = &x;         // int*
auto & b = x;          // int&
auto c = y;            // int*
auto * d = y;          // int*
auto * e = &foo();     // 编译失败, 指针不能指向一个临时变量
auto & f = foo();    // 编译失败, nonconst的左值引用不能和一个临时变量绑定
auto g = bar();      // int
auto & h = bar();    // int&

auto不继承引用,所以如果需要引用时需要自己添加,否则可能会引起拷贝,从而导致性能问题。

不继承cv限制符
double foo();
float * bar();
const auto a = foo();         // a: const double
const auto & b = foo();      // b: const double&
volatile auto * c = bar();   // c: volatile float*
auto d = a;                      // d: double
auto & e = a;                   // e: const double &
auto f = c;                      // f: float *
volatile auto & g = c;        // g: volatile float * &

同引用一样,auto不会继承const和volatile关键字,需要自己添加。

忽略*
#include <type_traits>
#include <iostream>
using namespace std;
int i = 1;
int & j = i;
int * p = &i;
const int k = 1;
int main() {auto* v3 = p;                  // v3的类型是int*v3 = &i;
}

auto在进行类型推导时,会对auto后冗余的*进行忽略,如p通过自动推导为int *,而auto*则不会被认为是int **,而是int *。

有些场合不适用
#include <vector>
using namespace std;
void fun(auto x =1){}  // 1: auto函数参数,无法通过编译
struct str{
auto var = 10;    // 2: auto非静态成员变量,无法通过编译
};
int main() {char x[3];auto y = x;auto z[3] = x; // 3: auto数组,无法通过编译// 4: auto模板参数(实例化时),无法通过编译vector<auto> v = {1};
}
// 编译选项:g++ -std=c++11 4-2-13.cpp

1)对于函数fun来说,auto不能是其形参类型。如果需要泛型的参数,还是需要求助于模板。

2)对于结构体来说,非静态成员变量的类型不能是auto的。同样的,由于var定义了初始值,读者可能认为auto可以推导str成员var的类型为int的。但编译器阻止auto对结构体中的非静态成员进行推导,即使成员拥有初始值。

3)声明auto数组。我们可以看到,main中的x是一个数组,y的类型是可以推导的,而声明auto z[3]这样的数组同样会被编译器禁止。

4)在实例化模板的时候使用auto作为模板参数,如main中我们声明的vector<auto> v。虽然读者可能认为这里一眼而知是int类型,但编译器却阻止了编译。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/235619.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

anconda常用命令

一、基础指令说明 1、查看anconda版本号 conda --version 2、查看当前已有虚拟环境 conda env list 3、创建新环境 conda create -n classify python3.9 创建一个叫做classify的虚拟环境&#xff0c;其中python等于3.9 4、进入虚拟环境 activate classify 5、安装包 接下来…

5213A 综合数据通信分析仪

5213A 综合数据通信分析仪 数字通信测量仪器 5213A 综合数据通信分析仪是符合标准 PXI/CPCI 总线的模块化便携式仪器&#xff0c;用户可以 根据测试需要选配相应的模块&#xff0c;可选模块包括双端口 RapidIO 模块、双端口 2G FC 模块、双 端口 4G FC 模块、双端口 8G FC 模…

HP服务器idrac设置以及系统安装

HP服务器idrac设置以及系统安装 一、设置管理口的地址和密码1、HP服务器重新界面选择"F9"进入BIOS&#xff0c;设置iLo5(idrac)的IP和用户名密码。2、选择"系统配置"。3、选择"iLO 4"配置程序。4、网络选项是设置idrac管理口的地址&#xff0c;设…

grafana基本使用

一、安装grafana 1.下载 官网下载地址&#xff1a; https://grafana.com/grafana/download官网包的下载地址&#xff1a; yum install -y https://dl.grafana.com/enterprise/release/grafana-enterprise-10.2.2-1.x86_64.rpm官网下载速度非常慢&#xff0c;这里选择清华大…

后端打包压缩包代码,前端接收响应下载

//临时工workbooks.zip文件 File zipFile File.createTempFile("workbooks", ".zip"); ZipOutputStream zipOutputStream new ZipOutputStream(new FileOutputStream(zipFile));for(..........){//临时workbook.xlsx文件,workbook写入xlsx中File tempFil…

Linux 操作系统(Vim)

vim 编译器&#xff08;相当于windows中记事本&#xff09; 当在终端窗口直接运行vim命令&#xff0c;会出现以下截图&#xff08;类似手册对vim编译器简单的介绍&#xff09;&#xff1a; vim提供三种基本工作模式&#xff1a; 命令模式(默认模式) 插入模式 末行模式 创建文本…

html之如何设置音频和视频?

文章目录 前言一、音频标签&#xff1a;audio1.audio简介2.常用属性controlsautoplayloop代码演示&#xff1a; 二、视频标签&#xff1a;video1.video2.常用的视频元素controlsautoplayloop代码演示&#xff1a; 总结视频元素总结音频元素总结 前言 html中插入音频和视频的方…

通信UART、I2C、SPI

内部通信UART、I2C、SPI 目录 1.UART 2.I2C 3.SPI 1.UART 全双工异步通信&#xff0c;有两根线发送与接收。 UART串口通信需要两个信号线来实现&#xff0c;一根用于串口发送&#xff0c;另外一根负责串口接收。 一开始高电平&#xff0c;然后拉低表示开始位&#xff0c;…

layui 树组件tree 通过API获取数据

一、简单 var treedata[];tree.render({elem: #addLeftType,id: demoId,data: treedata,showCheckbox: true,oncheck: function(obj){console.log(obj.data); // 得到当前点击的节点数据console.log(obj.checked); // 节点是否被选中console.log(obj.elem); // 得到当前节点元素…

java --- 反射

目录 一、什么是反射&#xff1f; 二、获取 Class对象 的三种方式 三、反射获取构造方法&#xff08;Constructor&#xff09; 四、反射获取成员变量&#xff08;Field&#xff09; 五、反射获取成员方法&#xff08;Method&#xff09; 一、什么是反射&#xff1f; 反射允…

app上架-您的应用在运行时,未同步告知权限申请的使用目的,向用户索取(相机)等权限,不符合华为应用市场审核标准。

上架提示 您的应用在运行时&#xff0c;未同步告知权限申请的使用目的&#xff0c;向用户索取&#xff08;相机&#xff09;等权限&#xff0c;不符合华为应用市场审核标准。 测试步骤&#xff1a;管理-添加-点击二维码&#xff0c;申请相机权限 修改建议&#xff1a;APP在调…

智能优化算法应用:基于非洲秃鹫算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于非洲秃鹫算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于非洲秃鹫算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.非洲秃鹫算法4.实验参数设定5.算法结果6.…

UE4 UE5 一直面向屏幕

一直面相屏幕&#xff0c;方法很简单 新建一个蓝图&#xff0c;如下添加组件&#xff1a; 蓝图如下&#xff1a; Rotation Actor &#xff1a;需要跟随镜头旋转的物体 Update&#xff1a;一个timeline&#xff08;替代event tick 只是为了循环&#xff09; Timeline&#xff…

百年东芝“瞄准”汽车「芯」机遇

在汽车“新四化”大变革的驱动下&#xff0c;汽车半导体市场进入需求暴涨的新周期。 “智能电动汽车所需要的半导体种类和数量正在急剧增加。” 东芝电子分立器件应用技术部经理成栋表示&#xff0c;东芝电子正在加大汽车半导体市场的布局&#xff0c;从而满足汽车电动化、智能…

深入了解Java中的锁机制

目录 1. synchronized关键字 1.1 基本概念 1.2 内置锁 1.3 限制 2. ReentrantLock 2.1 概述 2.2 公平性与非公平性 2.3 条件变量 3. 读写锁&#xff08;ReadWriteLock&#xff09; 3.1 概念 3.2 适用场景 4. StampedLock 4.1 概述 4.2 乐观读与悲观读 4.3 适用场…

Linux 操作系统 015-进程操作

Linux 操作系统 015-进程操作 本节关键字&#xff1a;Linux、进程操作、终止进程、进程树 本节相关指令&#xff1a;ps、pstree ps指令介绍 ps命令是用来查看目前系统中&#xff0c;有哪些正在执行&#xff0c;以及它们执行的状况&#xff0c;可以不加任何参数。 菜单栏介绍…

WT588F34B-16S语音芯片:四通道16K采样率混音播放的应用优势

随着科技的不断进步&#xff0c;语音芯片在电子产品中的应用越来越广泛。其中&#xff0c;WT588F34B-16S语音芯片凭借其卓越的性能和创新的功能&#xff0c;引起了市场的广泛关注。特别是其支持四通道16K采样率混音播放的功能&#xff0c;为实际应用带来了显著的优势。本文将深…

w13渗透测试实战之https账号密码捕抓

此次实验需要配合arp欺骗,不知道arp欺骗的&#xff0c;可以查看这篇w13渗透测试实战之ARP欺骗攻击&#xff08;ARP断网攻击&#xff09; 一、实验环境 攻击机&#xff1a;linux Kali 靶机&#xff1a;window 7 网络环境&#xff1a;虚拟机NAT 网关&#xff1a;192.168.89.2实…

Avalonia MVVM

Avalonia MVVM 是一种用于构建跨平台桌面应用程序的架构模式&#xff0c;它结合了 Avalonia UI 框架和 Model-View-ViewModel (MVVM) 设计模式。 以下是对 Avalonia MVVM 的各个部分的简要解释&#xff1a; Avalonia UI&#xff1a;Avalonia 是一个开源的跨平台 GUI&#xff0…

C11编写简易16位虚拟机

虚拟机 在计算领域&#xff0c;VM&#xff08;虚拟机&#xff09;是一个术语&#xff0c;指的是模拟/虚拟化计算机系统/架构的系统。 一般来说&#xff0c;虚拟机有两类&#xff1a; 系统虚拟机提供真实机器的完整替代品。 它们实现了足够的功能&#xff0c;允许操作系统在它…