zoukankan      html  css  js  c++  java
  • C++11 类型推导auto

    在C++11之前,auto关键字用来指定存储期。在新标准中,它的功能变为类型推断。auto现在成了一个类型的占位符,通知编译器去根据初始化代码推断所声明变量的真实类型。
    使用auto会拖慢c++效率吗?完全不会,因为在编译阶段编译器已经帮程序员推导好了变量的类型。
    使用auto会拖累C++编译效率吗?完全不会,因为在auto出现之前C++需要先推导等号右侧表达式的类型,然后检查它与变量的类型是否可以转换(兼容转换、向下类型转换和自定义类型转换)。auto出现之后,C++在推导出等号右侧表达式的类型之后,直接指定给变量。


    auto并非一种类型声明,而是类型声明时的占位符,编译器在编译时期会将auto替代为变量的实际类型。因此不能和typeid,sizeof一起使用。

    1.使用auto通常意味着更短的代码(除非你所用类型是int,它会比auto少一个字母)

    试想一下当你遍历STL容器时需要声明的那些迭代器(iterator),现在不需要去声明那些typedef就可以得到简洁的代码了。

    std::map<std::string, std::vector<int>> map;
    for(auto it = begin(map); it != end(map); ++it) {}

    2.返回值占位符

    auto不能用来声明函数的返回值,但如果函数有一个尾随的返回类型时,auto是可以出现在函数声明中返回值位置。这种情况下,auto并不是告诉编译器去推断返回类型,而是指引编译器去函数的末端寻找返回值类型。在下面这个例子中,函数的返回值类型就是operator+操作符作用在T1、T2类型变量上的返回值类型。

    template <typename T1, typename T2>
    auto compose(T1 t1, T2 t2) -> decltype(t1 + t2)
    {
       return t1+t2;
    }
    auto v = compose(2, 3.14); // v's type is double

    3.auto声明的变量必须初始化

    int main()
    {
        auto m = 1; 
        auto n{1};
        auto z = new auto(10);
        
        auto a;                 //错误,未初始化
        auto int b = 1;         //错误,auto不能和其它类型一起使用(C++98和C中可以)
        auto c = new auto();    //错误,没有初始化
        auto d = 1, e = 2.01;   //错误,定义在一个auto序列的变量必须始终推导成同一类型
        
        return 0;
    }

    4.C++标准中规定auto可以与CV(const & volatile qualifiers)限制符一起使用,不过声明为auto的变量不能从其初始化表达式中带走CV限制符

    从const变量推导或用auto接收从函数返回的const变量,会丢失const属性,除非显示声明为引用类型。

    从引用变量推导或用auto接收从函数返回的引用变量,会丢失引用特性,除非显示声明为引用类型。

    #include <iostream>
    #include <typeinfo>
    #include <vector>
    
    using namespace std;
    
    struct student
    {
        std::string name;
        int age;
        student(std::string name, int age)
        : name(name)
        , age(age)
        {
            std::cout << "constructor" << std::endl;
        }
    
        student(const student& rhs)
        {
            std::cout << "copy constructor" << std::endl;
            this->name = rhs.name;
            this->age = rhs.age;
        }
    };
    
    student& backRef(student& s)
    {
        return s;
    }
    
    int main()
    {
        const auto var1 = 1;        //var1为const int
        auto var2 = var1;           //var1为int(除非var2声明为:auto& var2类型)
        auto& var3 = var1;          //var3为const int
        var2 = 3;                   //经过auto推导,var2变量已经丢失了const属性
        //var3 = 5;                 //错误,const变量禁止修改
    
        auto var4 = 4;
        auto& var5 = var4;          //var5是var4的引用类型
        var5 = 6;
        auto var6 = var5;           //从var5中推导,只会获得变量类型,会丢失引用特性
        var6 = 10;
        std::cout << "var4:" << var4 << std::endl;
        std::cout << "var5:" << var5 << std::endl;
        std::cout << "var6:" << var6 << std::endl;
    
        student stu1{"sanz", 10};
        auto stu2 = stu1;
    
        auto stu3 = backRef(stu1);  //函数返回引用类型,但实际会调用拷贝构造函数
        stu3.age = 12;
        auto& stu4 = backRef(stu1); //显示添加引用后,还是stu1
        stu4.age = 18;
        std::cout << stu1.age << std::endl;
        std::cout << stu2.age << std::endl;
        std::cout << stu3.age << std::endl;
        std::cout << stu4.age << std::endl;
    
        return 0;
    }
    View Code

    auto也不是万能的,受制于语法的二义性,或者是实现的困难性,auto往往也有使用上的限制。

    #include <iostream>
    #include <typeinfo>
    #include <vector>
    
    using namespace std;
    
    struct str
    {
        auto var = 10;      //1.a通过编译auto非静态成员变量,无法
    };
    
    void fun(auto x)        //2.auto函数参数,无法通过编译
    {
    }
    
    int main()
    {
        int x[3];
        auto y = x;
        auto z[3] = x;      //3.auto数组,无法通过编译
        
        //auto模版参数,无法通过编译
        vector<auto> v = {1};
        
        return 0;
    }

    分析一下上述4中不能推导的情况:

    1.对于函数fun来说,auto不能是其形参类型。由于其有默认参数,所以应该推导fun形参x的类型为int型。但事实无法符合大家的想象,如果程序员需要泛型的参数,还是求助与模版。

    2.对于结构体或类来说,非静态成员变量的类型不能为auto。编译器阻止auto对结构体中的非静态成员进行推导,即使成员拥有初始值。

    3.声明auto数组。x是一个数组,y类型是可以推导的,而声明auto z[3]这样的数字同样会被编译器禁止。

    4.在实例化模版的时候使用auto作为模版参数,虽然读者认为这里一眼而知是int类型,但编译器却阻止了编译。

  • 相关阅读:
    「UVA12293」 Box Game
    「CF803C」 Maximal GCD
    「CF525D」Arthur and Walls
    「CF442C」 Artem and Array
    LeetCode lcci 16.03 交点
    LeetCode 1305 两棵二叉搜索树中的所有元素
    LeetCode 1040 移动石子直到连续 II
    LeetCode 664 奇怪的打印机
    iOS UIPageViewController系统方法崩溃修复
    LeetCode 334 递增的三元子序列
  • 原文地址:https://www.cnblogs.com/DswCnblog/p/6520555.html
Copyright © 2011-2022 走看看