• C++ auto



    前言:在早期C/C++中auto关键字的作用是:一个存储类型指示符,使用auto修饰的变量,存储类型为自动存储期,从变量声明处生命周期开始,出变量所在代码块生命周期结束,并且 全局变量不能用auto修饰。但是局部变量的生命周期本来就是进入作用域生命周期开始,出作用域生命周期结束。 导致用auto修饰局部变量和不使用auto修饰没有任何区别,处于一个尴尬地步。

    一、C++ 11

     C++11中,标准委员会赋予了auto全新的作用:auto做为类型占位符auto声明的变量数据类型由编译器在编译时推导而得,所以使用auto声明变量时必须对其进行初始化,在编译阶段编译器根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型

    #include 
    
    using namespace std;
    
    int main()
    {
    	int x = 10;
    	auto y = x; // 因为x为int类型,所以等同于 int y = x;
    	auto a = 'a'; // 因为a为char类型,所以等同于 char a = 'a';
    	auto b = 1; // 因为b为int类型,所以等同于 int b = 1;
    	auto c = 3.14; // 因为c为double类型,所以等同于 double c = 3.14;
    	// auto d; 错误,无法推导d是什么类型,导致不能分配内存空间
    	cout << "y:" << typeid(y).name() << endl;
    	cout << "a:" << typeid(a).name() << endl;
    	cout << "b:" << typeid(b).name() << endl;
    	cout << "c:" << typeid(c).name() << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    输出:

    y:int
    a:char
    b:int
    c:double
    
    • 1
    • 2
    • 3
    • 4

    注意:使用auto对多个变量推导时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器按第一个变量类型进行推导,然后用推导出来的类型定义其他变量

    auto a = 10, b = 20; // 正确
    auto x = 1, y = 3.14; // 错误,第一个变量x类型为int,但y为double
    
    • 1
    • 2

    1.1 推导规则

    规则1: auto 会删除引用、const 限定符和 volatile 限定符

    const int i = 1;
    auto a = i; // auto推导类型为int,而不是const int
    
    int j = 2;
    int &ref = j;
    auto b = ref; // ref为引用,auto推导会删除引用属性,auto推导类型为int,b类型为int
    auto &c = ref; // ref为引用,auto推导类型为int,c类型为int&
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    规则2: auto推导指针类型时,autoauto*没有任何区别。

    const int i = 1;
    
    auto a = &i; // auto推导类型为const int*,a类型为const int*
    auto* b = &i; // auto推导类型为const int,b类型为const int*
    
    • 1
    • 2
    • 3
    • 4

    规则3: auto推导目标对象是数组或函数时,会被推导为对应指针类型

    void fun() {
        std::cout << "test" << std::endl;
    }
    
    int arr[] = {1, 2, 3};
    
    auto a = arr; // auto推导类型为int * 
    auto b = fun; // auto推导类型为void (*)()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    规则4 auto推导列表表达式

    注意:下面规则适用于C++ 17

    • 直接使用列表初始化,列表中必须为单元素,否则编译错误,auto推导类型为该元素类型
    • 用等号加列表初始化,列表中可以包含多个类型相同的元素,auto推导类型为std::initializer_list,其中T为元素类型
    auto a1{3}; // auto推导类型为int
    auto a2{1, 3}; // 编译错误,不是单个元素
    auto a3 = {1, 2, 3}; // auto推导类型为std::initializer_list
    auto a4 = {1, 1.1}; // 编译错误,列表内元素类型不同
    
    • 1
    • 2
    • 3
    • 4

    1.2 auto不能使用的场景

    1.2.1 auto 不能做为函数形参

    int add(auto x, auto y) // 错误,auto不能做函数形参,编译器不知道如何为形参分配空间
    {
    	return x + y;
    }
    
    • 1
    • 2
    • 3
    • 4

    1.2.2 auto 不能声明数组

    auto arr[] = {123}; // 错误
    
    • 1

    二、C++ 14

    2.1 函数返回值类型推导

    C++ 14支持使用auto对函数返回值类型进行推导,但要确保所有的返回值类型是相同的。

    auto add(int i,int j) // 正确
    {
        return i+j;
    }
    
    auto add(double i,double j) // 错误,0为int类型,i+j为double类型,返回值类型不相同
    {
    	if(i < 0.0 || j < 0.0)
    		return 0;
    	else
    		return i + j;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.2 lambda

    C++14支持在lambda中使用auto作为形参以及返回值类型推导。

    auto f = [](auto x, auto y) // lambda中使用auto对函数形参类型推导
    {
        return x + y;
    };
    
    auto ret1 = f(1, 2); // ret1 = 3
    auto ret2 = f(1, 2.2); // ret2 = 3.2
    
    
    auto f = [](auto &x) ->auto& // lambda可以使用auto推导返回值类型,或者auto&返回引用
    {
        return x;
    };
    
    int x = 1;
    cout << "&x:" << &x << endl;
    auto& ref = f(x);
    cout << "&ref:" << &ref << endl; // &x 与 &ref有相同地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    三、C++ 17

    3.1 非类型模版参数

    C++ 17支持auto作为非类型模版参数的占位符,但推导出来的类型必须是符合非类型模版参数类型要求的,否则编译会错误。

    template <auto N>
    void f()
    {
        cout << N << endl;
    }
    
    f<1>(); // 正确
    f<'a'>(); // 正确
    f<3.14>(); // 错误,浮点类型不能作为非类型模版参数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    SpringBoot2.7.4整合Redis
    docker系统架构
    LeetCode_Array_42. Trapping Rain Water 接雨水【双指针】【Java】【困难】
    Gitee崩了?大量仓库被关闭,官方答复“迫于无奈”
    springboot整合消息队列——RabbitMQ
    MySQL之库操作
    python-(6-3-1)爬虫---requests入门
    Linux网络-HTTP协议
    华为7年经验的软件测试总监,给所有想转行学软件测试的同学的几个建议
    电子器件系列44:环形线圈电感
  • 原文地址:https://blog.csdn.net/kjl167/article/details/138169042