一. auto简介

编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型。然而做到这一点并非那么容易(特别是模板中),有时候根本做不到。为了解决这个问题,C++11新标准就引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。和原来那些只对应某种特定的类型说明符(例如 int)不同。auto 让编译器通过初始值来进行类型推演。从而获得定义变量的类型,所以说 auto 定义的变量必须有初始值。

    //由val_1 和val_2相加的结果可以推断出item的类型
    auto item = val_1 + val_2;//item 类型初始化为val_1 + val_2相加后的类型,值为val_1+val_2相加的值。

    这里的 item 的类型是编译器在编译的过程中通过val_1和val_2的类型相加后推算出来的。假如是val_1(int) + val_2(double),那么item的类型就是double.

            使用auto也能在一个语句中声明多个变量,因为一个声明雨具只能有一个基本数据类型,所以该雨具所有变量的初始基本数据类型都必须是一样的。在这里一定要区别数据类型和类型修饰符!!

    int i = 3;
    auto a = i,&b = i,*c = &i;//正确: a初始化为i的副本,b初始化为i的引用,c为i的指针.
    auto sz = 0, pi = 3.14;//错误,两个变量的类型不一样。

            编译器推断出来的auto类型有时候会跟初始值的类型并不完全一样,编译器会适当的改变结果类型使得其更符合初始化规则。

            首先,正如我们熟知的,使用引用其实是使用引用的对象,特别当引用被用作初始值的时候,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型:

    int i = 0 ,&r = i;//定义一个整数i,并且定义r为i的应用.
    auto a = r; //这里的a为为一个整数,其值跟此时的i一样.

            由此可以看出auto会忽略引用,其次,auto一般会忽略掉顶层const,但底层const会被保留下来,比如当初始值是一个指向常量的指针时:

 

        int i = 0;
        const int ci = i, &cr = ci;  //ci 为整数常量,cr 为整数常量引用
        auto a = ci;     // a 为一个整数, 顶层const被忽略
        auto b = cr;     // b 为一个整数,顶层const被忽略
        auto c = &ci;    // c 为一个整数指针.
        auto d = &cr;    // d 为一个指向整数常量的指针(对常量对象区地址是那么const会变成底层const)

            如果你希望推断出auto类型是一个顶层的const,需要明确指出:

const auto f = ci;

            还可以将引用的类型设为auto,此时原来的初始化规则仍然适用(用于引用声明的const都是底层const):

    auto &g = ci; //g是一个整数常量引用,绑定到ci。
    auto &h = 42; // 错误:非常量引用的初始值必须为左值。
    const auto &j = 42; //正确:常量引用可以绑定到字面值。

二. decltype简介

            有的时候我们还会遇到这种情况,我们希望从表达式中推断出要定义变量的类型,但却不想用表达式的值去初始化变量。还有可能是函数的返回类型为某表达式的的值类型。在这些时候auto显得就无力了,所以C++11又引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器只是分析表达式并得到它的类型,却不进行实际的计算表达式的值。

decltype(f()) sum = x;// sum的类型就是函数f的返回值类型。

          

            在这里编译器并不实际调用f函数,而是分析f函数的返回值作为sum的定义类型。

            基本上decltype的作用和auto很相似,就不一一列举了。对于decltype还有一个用途就是在c++11引入的后置返回类型。

三. decltype 和 auto 区别

            decltype在处理顶层const和引用的方式与auto有些许不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内)。

        const int ci = 42, &cj = ci;
     
        decltype(ci) x = 0;   // x 类型为const int
        auto z = ci;          // z 类型为int
     
        decltype(cj) y = x;   // y 类型为const int&
        auto h = cj;          // h 类型为int

           decltype还有一些值得注意的地方,我们先来看看下面这段代码:

        int i = 42, *p = &i, &r = i;
     
        decltype(i) x1 = 0;       //因为 i 为 int ,所以 x1 为int
        auto x2 = i;              //因为 i 为 int ,所以 x2 为int
     
        decltype(r) y1 = i;       //因为 r 为 int& ,所以 y1 为int&
        auto y2 = r;              //因为 r 为 int& ,但auto会忽略引用,所以 y2 为int
     
        decltype(r + 0) z1 = 0;   //因为 r + 0 为 int ,所以 z1 为int,
        auto z2 = r + 0;          //因为 r + 0 为 int ,所以 z2 为int,
     
        decltype(*p) h1 = i;      //这里 h1 是int&, 原因后面讲
        auto h2 = *p;             // h2 为 int.

           如果表达式的内容是解引用操作,则decltype将得到引用类型。正如我们所熟悉的那样,解引用指针可以得到指针所指对象,而且还可以给这个对象赋值。因此decltype(*p)的结果类型就是int&.

           decltype和auto还有一处重要的区别是,decltype的结果类型与表达形式密切相关。有一种情况需要特别注意:对于decltype 所用表达式来说,如果变量名加上一对括号,则得到的类型与不加上括号的时候可能不同。如果decltype使用的是一个不加括号的变量,那么得到的结果就是这个变量的类型。但是如果给这个变量加上一个或多层括号,那么编译器会把这个变量当作一个表达式看待,变量是一个可以作为左值的特殊表达式,所以这样的decltype就会返回引用类型:

        int i = 42;
     
        //decltype(i)   int  类型
        //decltype((i)) int& 类型

           这里再指出一个需要注意的地方就是 = 赋值运算符返回的是左值的引用。换句话意思就是说 decltype(i = b)  返回类型为 i 类型的引用。仔细看下面这段代码:

    int main()
    {
        int i = 42;
     
        decltype(i = 41) x = i;
     
        auto y = i;
     
        auto& z = i;
     
        printf("i x y z 此时为: %d %d %d %d\n", i,x,y,z);
     
        i--;
     
        printf("i x y z 此时为: %d %d %d %d\n", i, x, y, z);
     
        x--;
     
        printf("i x y z 此时为: %d %d %d %d\n", i, x, y, z);
     
        y--;
     
        printf("i x y z 此时为: %d %d %d %d\n", i, x, y, z);
     
        z--;
     
        printf("i x y z 此时为: %d %d %d %d\n", i, x, y, z);
     
        return 0;
    }

运行结果为:

i x y z 此时为: 42 42 42 42
i x y z 此时为: 41 41 42 41
i x y z 此时为: 40 40 42 40
i x y z 此时为: 40 40 41 40
i x y z 此时为: 39 39 41 39

     
           由上面的代码和运行结果可以看出来,1.decltype(i = 41)中的赋值语句并没有真正的运行。2. decltype(i = 41)返回的其实是int&,也就是说x 其实是 i 的引用。

了解了auto 和 decltype后,以后在使用的过程中一定要分清两者的区别,防止在定义的时候产生const 与非const 以及引用 与非引用 的差别!!
————————————————
版权声明:本文为CSDN博主「YzlCoder」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/y1196645376/article/details/51441503

C++ 11 新特性: auto 和 decltype 区别和联系的更多相关文章

  1. C++11新特性— auto 和 decltype 区别和联系

    一. auto简介 编程时候常常需要把表达式的值付给变量,需要在声明变量的时候清楚的知道变量是什么类型.然而做到这一点并非那么容易(特别是模板中),有时候根本做不到.为了解决这个问题,C++11新标准 ...

  2. 【C++11】新特性——auto的使用

    [C++11]新特性——auto的使用 C++11中引入的auto主要有两种用途:自动类型推断和返回值占位.auto在C++98中的标识临时变量的语义,由于使用极少且多余,在C++11中已被删除.前后 ...

  3. [转载] C++11新特性

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

  4. 在C++98基础上学习C++11新特性

    自己一直用的是C++98规范来编程,对于C++11只闻其名却没用过其特性.近期因为工作的需要,需要掌握C++11的一些特性,所以查阅了一些C++11资料.因为自己有C++98的基础,所以从C++98过 ...

  5. C++11新特性总结 (二)

    1. 范围for语句 C++11 引入了一种更为简单的for语句,这种for语句可以很方便的遍历容器或其他序列的所有元素 vector<int> vec = {1,2,3,4,5,6}; ...

  6. C++11新特性总结 (一)

    1. 概述 最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己写了,看别人写的代码估计都会有些吃力.C++ Primer5是学习C++1 ...

  7. C++11 新特性之智能指针(shared_ptr, unique_ptr, weak_ptr)

    这是C++11新特性介绍的第五部分,涉及到智能指针的相关内容(shared_ptr, unique_ptr, weak_ptr). shared_ptr shared_ptr 基本用法 shared_ ...

  8. c++11新特性注意点

    本文记录下一些c++11新特性需要注意的方面,供日后参考 一.auto auto可以当成“占位符”,根据右边的类型自动推导出变量的类型.需要注意的是 auto不能解决溢出的问题. auto可以与指针和 ...

  9. c++ 11 线程池---完全使用c++ 11新特性

    前言: 目前网上的c++线程池资源多是使用老版本或者使用系统接口实现,使用c++ 11新特性的不多,最近研究了一下,实现一个简单版本,可实现任意任意参数函数的调用以及获得返回值. 0 前置知识 首先介 ...

  10. C++ 11 新特性

    C++11新特性:          1.auto          2.nullptr          3.for          4.lambda表达式          5.override ...

随机推荐

  1. Java设计模式之(十)——组合模式

    1.什么是组合模式? Compose objects into tree structures to represent part-whole hierarchies.Composite lets c ...

  2. 洛谷 P6624 - [省选联考 2020 A 卷] 作业题(矩阵树定理+简单数论)

    题面传送门 u1s1 这种题目还是相当套路的罢 首先看到 \(\gcd\) 可以套路地往数论方向想,我们记 \(f_i\) 为满足边权的 \(\gcd\) 为 \(i\) 的倍数的所有生成树的权值之和 ...

  3. CF1278F Cards

    CF1278F Cards 首先我们知道,一次拿牌的概率是 $ P(i) = \frac 1 m $ ,同时权值是1,所以期望就是 $ \frac{1} m $,拿 $ n $ 次牌贡献是独立的,就是 ...

  4. 洛谷 P3343 - [ZJOI2015]地震后的幻想乡(朴素状压 DP/状压 DP+微积分)

    题面传送门 鸽子 tzc 竟然来补题解了,奇迹奇迹( 神仙题 %%%%%%%%%%%% 解法 1: 首先一件很明显的事情是这个最小值可以通过类似 Kruskal 求最小生成树的方法求得.我们将所有边按 ...

  5. R语言与医学统计图形【8】颜色的选取

    R语言基础绘图系统 基础绘图包之低级绘图函数--内置颜色. 1.内置颜色选取 功能657种内置颜色.colors() 调色板函数:palette(), rgb(), rainbow(). palett ...

  6. Linux运维工程师面试题整理

    1. Nginx 反向代理,负载均衡,动静分离,工作原理及优化nginx配置反向代理. vim Nginx.confServer模块中配置Listen 80Server_name ip;在server ...

  7. C语言 字符串指针和字符串数组使用区别

    字符串指针和字符串数组使用区别 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 ...

  8. SpringCloud微服务实战——搭建企业级开发框架(二十八):扩展MybatisPlus插件DataPermissionInterceptor实现数据权限控制

    一套完整的系统权限需要支持功能权限和数据权限,前面介绍了系统通过RBAC的权限模型来实现功能的权限控制,这里我们来介绍,通过扩展Mybatis-Plus的插件DataPermissionInterce ...

  9. 巩固javaweb的第二十三天

    巩固内容: 调用验证方法 验证通常在表单提交之前进行,可以通过按钮的 onClick 事件,也可以通过 form 表单 的 onSubmit 事件来完成. 本章实例是通过 form 表单的 onSub ...

  10. 学习java 7.11

     学习内容: 泛型定义格式:<类型> 优点:把运行时期的问题提前到编译期间:避免了强制类型转换   泛型方法:public class Fanxing { public <T> ...