前言

这个东西在新版本的 C 语言中还是很常用的,尤其是用到 for 循环中。蒟蒻之前也是对这个了解不多,基本没用过(除非迫不得已,因为我的C++编译器太逊了,不支持此操作,用这个操作还得用在线 IDE,很麻烦),现在觉得有必要来整理整理了。

C++98 auto

早在C++98标准中就存在了auto关键字,那时的auto用于声明变量为自动变量,自动变量意为拥有自动的生命期,这是多余的,因为就算不使用auto声明,变量依旧拥有自动的生命期:

int a =10 ;  //拥有自动生命期
auto int b = 20 ;//拥有自动生命期
static int c = 30 ;//延长了生命期

C++98 中的 auto 多余且极少使用,C++11 已经删除了这一用法,取而代之的是全新的 auto:变量的自动类型推断。

C++11 auto

auto 可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型,类似的关键字还有decltype。举个例子:

    int a = 10;
auto au_a = a;//自动类型推断,au_a为int类型
cout << typeid(au_a).name() << endl;

typeid运算符可以输出变量的类型。程序的运行结果输出了.

这种用法就类似于C#中的var关键字。auto的自动类型推断发生在编译期,所以使用auto并不会造成程序运行时效率的降低。而是否会造成编译期的时间消耗,我认为是不会的,在未使用auto时,编译器也需要得知右操作数的类型,再与左操作数的类型进行比较,检查是否可以发生相应的转化,是否需要进行隐式类型转换。

auto的用法

上面举的这个例子很简单,在真正编程的时候也不建议这样来使用auto,直接写出变量的类型更加清晰易懂。下面列举auto关键字的正确用法。

用于代替冗长复杂、变量使用范围专一的变量声明。

想象一下在没有auto的时候,我们操作标准库时经常需要这样:

#include<string>
#include<vector>
int main()
{
std::vector<std::string> vs;
for (std::vector<std::string>::iterator i = vs.begin(); i != vs.end(); i++)
{
//...
}
}

这样看代码写代码实在烦得很。有人可能会说为何不直接使用using namespace std,这样代码可以短一点。实际上这不是该建议的方法(C++Primer对此有相关叙述)。使用auto能简化代码:

#include<string>
#include<vector>
int main()
{
std::vector<std::string> vs;
for (auto i = vs.begin(); i != vs.end(); i++)
{
//..
}
}

for循环中的i将在编译时自动推导其类型,而不用我们显式去定义那长长的一串。

在定义模板函数时,用于声明依赖模板参数的变量类型。

template <typename _Tx,typename _Ty>
void Multiply(_Tx x, _Ty y)
{
auto v = x*y;
std::cout << v;
}

若不使用auto变量来声明v,那这个函数就难定义啦,不到编译的时候,谁知道x*y的真正类型是什么呢?

模板函数依赖于模板参数的返回值

template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty)
{
return x*y;
}

当模板函数的返回值依赖于模板的参数时,我们依旧无法在编译代码前确定模板参数的类型,故也无从知道返回值的类型,这时我们可以使用auto。格式如上所示。

decltype操作符用于查询表达式的数据类型,也是C++11标准引入的新的运算符,其目的也是解决泛型编程中有些类型由模板参数决定,而难以表示它的问题。

auto在这里的作用也称为返回值占位,它只是为函数返回值占了一个位置,真正的返回值是后面的decltype(_Tx*_Ty)。为何要将返回值后置呢?如果没有后置,则函数声明时为:

decltype(_Tx*_Ty)multiply(_Tx x, _Ty y)

而此时_Tx,_Ty还没声明呢,编译无法通过。

注意事项

  • auto 变量必须在定义时初始化,这类似于const关键字。

  • 定义在一个auto序列的变量必须始终推导成同一类型。例如:

    auto a4 = 10, a5 = 20, a6 = 30;//正确
auto b4 = 10, b5 = 20.0, b6 = 'a';//错误,没有推导为同一类型

使用auto关键字做类型自动推导时,依次施加一下规则:

  • 如果初始化表达式是引用,则去除引用语义。
    int a = 10;
int &b = a; auto c = b;//c的类型为int而非int&(去除引用)
auto &d = b;//此时c的类型才为int& c = 100;//a =10;
d = 100;//a =100;
  • 如果初始化表达式为const或volatile(或者两者兼有),则除去const/volatile语义。
    const int a1 = 10;
auto b1= a1; //b1的类型为int而非const int(去除const)
const auto c1 = a1;//此时c1的类型为const int
b1 = 100;//合法
c1 = 100;//非法
  • 如果auto关键字带上&号,则不去除const语意。
    const int a2 = 10;
auto &b2 = a2;//因为auto带上&,故不去除const,b2类型为const int
b2 = 10; //非法

这是因为如何去掉了const,则b2为a2的非const引用,通过b2可以改变a2的值,则显然是不合理的。

  • 初始化表达式为数组时,auto关键字推导类型为指针。
    int a3[3] = { 1, 2, 3 };
auto b3 = a3;
cout << typeid(b3).name() << endl;
  • 若表达式为数组且auto带上&,则推导类型为数组类型。
    int a7[3] = { 1, 2, 3 };
auto & b7 = a7;
cout << typeid(b7).name() << endl;
  • 函数或者模板参数不能被声明为auto
void func(auto a)  //错误
{
//...
}
  • 时刻要注意auto并不是一个真正的类型。auto仅仅是一个占位符,它并不是一个真正的类型,不能使用一些以类型为操作数的操作符,如sizeof或者typeid。
    cout << sizeof(auto) << endl;//错误
cout << typeid(auto).name() << endl;//错误

auto关键词的更多相关文章

  1. C/C++中的auto关键词

    C语言 auto被解释为一个自动存储变量的关键字,也就是申明一块临时的变量内存. 例如: auto double a=3.7; 表示a为一个自动存储的临时变量. C++语言 C++ 98标准/C++0 ...

  2. C++隐式推导-auto关键词

    总述 C++中有一个关键字,它不进行显式声明,而进行隐式推导,auto可以在声明变量时根据变量初始值的类型自动为此变量选择匹配的类型.C++语言类似的关键字还有decltype. 如何评价 C++ 1 ...

  3. C++11 auto and decltype

    1.auto关键字 C++新标准引入auto关键词,此auto与之前C语言的auto意义已经不一样了. 这里的auto是修饰未知变量的类型,编译器会通过此变量的初始化自动推导变量的类型. 例如:aut ...

  4. C++0X 学习之 auto

    auto并不是一个新关键词,是一个把旧关键词赋予新的作用,新的作用修饰变量声明,指示编译器根据变量的初始化表达式推导变量应有的类型.auto 声明的变量必须“在声明处完成初始化”,编译器才可根据初始化 ...

  5. C++ 14 auto

    C++14标准最近刚被通过,像以前一样,没有给这个语言带来太大变化,C++14标准是想通过改进C++11 来让程序员更加轻松的编程,C++11引入auto关键字(严格来说auto从C++ 03 开始就 ...

  6. linux进程的堆栈空间_代码段(指令,只读)、数据段(静态变量,全局变量)、堆栈段(局部变量)、栈【转】

    转自:http://blog.csdn.net/gongweijiao/article/details/8207333 原文参见:http://blog.163.com/xychenbaihu@yea ...

  7. C++ Primer 5th 第12章 动态内存

    练习12.1:在此代码的结尾,b1 和 b2 各包含多少个元素? StrBlob b1; { StrBlob b2 = {"a", "an", "th ...

  8. 【C和指针】笔记1

    数据 基本数据类型 整型家族:包含字符,短整型,整型和长整型 整型相互之间大小规定如下: 长整型至少和整型一样长,而整型至少应该和短整型一样长. short int至少16位,long int至少32 ...

  9. 与C/C++关键字extern有关的原理

    关键字有一定的语义,但是用法不唯一. 对于C/C++语言的预编译.编译.汇编.链接.我相信大家在接触C++一年不到就背的滚瓜烂熟,但是其中的细节,是后来才慢慢想明白的.为什么我不讲extern关键字呢 ...

  10. c++处理类型与自定义数据结构

    1.typedef 类型别名 有时我们在阅读c++程序时,发现一些未见过的类型,这实际上就是typedef导致的,使用很简单,如下: typedef int wayne; wayne a = , b ...

随机推荐

  1. 2021-7-12 VUE的过滤器使用

    过滤器实例:转换首字母大写 <!DOCTYPE html> <html> <head> <title> </title> </head ...

  2. IOS App内嵌H5 swiper 轮播出现卡顿白屏闪烁

    话说在前头:前端开发同学遇到这个问题不慌,因为接下来你要踩的坑我都帮你们踩完了,所以有了这一篇博客.希望能帮到你 轮播组件:swiper@4.5.1 (4x稳定的最后一个版本) 设备:ios版本15x ...

  3. MyBatis Mapper映射处理CLOB和BLOB类型

    ​Mybatis的MapperXML映射文件应该处理数据库字段类型为CLOB和BLOB类型的数据呢?首先我们先看下CLOB和BLOB这两种数据类型的介绍. 介绍 使用Mybatis时涉及到两种特殊类型 ...

  4. 1、MyBatis简介

    1.1.MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁 移到了Google Code. ...

  5. cockpit--一款开源的适用于单主机的Linux监控面板

    在搜索Linux监控时,偶然发现一款还不错的监控面板,该面板为red hat开发,适用于各种Linux发行版,部署也非常方便,官方文档Running Cockpit - Cockpit Project ...

  6. 《SQL与数据库基础》10. 存储引擎

    目录 存储引擎 MySQL体系结构 存储引擎简介 三种经典存储引擎 InnoDB 逻辑存储结构 MyISAM Memory 区别及特点 存储引擎选择 本文以 MySQL 为例 存储引擎 MySQL体系 ...

  7. java与es8实战之六:用JSON创建请求对象(比builder pattern更加直观简洁)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<java与es8实战>系 ...

  8. 给你的 SpringBoot 工程部署的 jar 包瘦瘦身吧!

    之前有写过一篇有关maven插件的文章:spring-boot-maven-plugin插件详解 一.需求背景 我们知道Spring Boot项目,是可以通过java -jar 包名 启动的. 那为什 ...

  9. springcache+redis实战

    前言 有兴趣的同学,可以看我上一篇文章,然后再过来看会比较清楚点:https://www.cnblogs.com/yhc-910/p/14884678.html springcache,简单说,就是用 ...

  10. 为什么 Python 代码在函数中运行得更快?

    哈喽大家好,我是咸鱼 当谈到编程效率和性能优化时,Python 常常被调侃为"慢如蜗牛" 有趣的是,Python 代码在函数中运行往往比在全局范围内运行要快得多 小伙伴们可能会有这 ...