(P5-P7)使用auto进行类型自动推导

1.auto

在 C++11 之前 auto 和 static 是对应的,表示变量是自动存储的,但是非 static 的局部变量默认都是自动存储的,因此这个关键字变得非常鸡肋。

  • 在C++11 中他们赋予了新的含义,使用这个关键字能够像别的语言一样自动推导出变量的实际类型。

推导规则

  • C++11 中 auto 并不代表一种实际的数据类型,只是一个类型声明的 “占位符”,auto 并不是万能的在任意场景下都能够推导出变量的实际类型,使用auto声明的变量必须要进行初始化,以让编译器推导出它的实际类型,在编译时将auto占位符替换为真正的类型。
  • 使用语法如下:
auto 变量名 = 变量值;
  • eg:
auto x = 3.14;      // x 是浮点型 double
auto y = 520;       // y 是整形 int
auto z = 'a';       // z 是字符型 char
auto nb;            // error,变量必须要初始化
auto double nbl;    // 语法错误, 不能修改数据类型   

auto 还可以和指针、引用结合起来使用也可以带上 const、volatile 限定符,在不同的场景下有对应的推导规则,规则内容如下:

  • 当变量不是指针或者引用类型时,推导的结果中不会保留 const、volatile 关键字

  • 当变量是指针或者引用类型时,推导的结果中会保留 const、volatile 关键字

  • eg:一组变量带指针和引用并使用 auto 进行类型推导的例子

int temp = 110;

变量 a 的数据类型为 int*,因此 auto 关键字被推导为 int类型
auto *a = &temp;	

变量 b 的数据类型为 int*,因此 auto 关键字被推导为 int* 类型
auto b = &temp;		

变量 c 的数据类型为 int&,因此 auto 关键字被推导为 int类型
auto &c = temp;		

变量 d 的数据类型为 int,因此 auto 关键字被推导为 int 类型
auto d = temp;
  • eg:一组带 const 限定的变量,使用 auto 进行类型推导的例子
int tmp = 250;

变量 a1 的数据类型为 const int,因此 auto 关键字被推导为 int 类型
const auto a1 = tmp;

变量 a2 的数据类型为 int,但是 a2 没有声明为指针或引用因此 const 属性被去掉,auto 被推导为 int
auto a2 = a1;

变量 a3 的数据类型为 const int&,a3 被声明为引用,因此 const 属性被保留,auto 关键字被推导为 int 类型
const auto &a3 = tmp;

变量 a4 的数据类型为 const int&,a4 被声明为引用因此 const 属性被保留,auto 关键字被推导为 const int 类型
auto &a4 = a3;

2.auto 的限制

auto 关键字并不是万能的,在以下这些场景中是不能完成类型推导的:

  • 不能作为函数参数使用。因为只有在函数调用的时候才会给函数参数传递实参,auto 要求必须要给修饰的变量赋值,因此二者矛盾。
int func(auto a, auto b)	// error
{	
    cout << "a: " << a <<", b: " << b << endl;
}
  • 不能用于类的非静态成员变量的初始化
class Test
{
    auto v1 = 0;                    // error
    static auto v2 = 0;             // error,类的静态非常量成员不允许在类内部直接初始化
    static const auto v3 = 10;      // ok
}
  • 不能使用 auto 关键字定义数组
int func()
{
    int array[] = {1,2,3,4,5};  // 定义数组
    auto t1 = array;            // ok, t1被推导为 int* 类型
    auto t2[] = array;          // error, auto无法定义数组
    auto t3[] = {1,2,3,4,5};;   // error, auto无法定义数组
}
  • 无法使用 auto 推导出模板参数
template <typename T>
struct Test{}

int func()
{
    Test<double> t;
    Test<auto> t1 = t;           // error, 无法推导出模板类型
    return 0;
}

3.auto 的应用

  • 用于STL的容器遍历。
    在 C++11 之前,定义了一个 stl 容器之后,遍历的时候常常会写出这样的代码:
#include <map>
int main()
{
    map<int, string> person;
    map<int, string>::iterator it = person.begin();
    for (; it != person.end(); ++it)
    {
        // do something
    }
    return 0;
}

可以看到在定义迭代器变量 it 的时候代码是很长的,写起来就很麻烦,使用了 auto 之后,就变得清爽了不少:
#include <map>
int main()
{
    map<int, string> person;
    // 代码简化
    for (auto it = person.begin(); it != person.end(); ++it)
    {
        // do something
    }
    return 0;
}
  • 用于泛型编程,在使用模板的时候,很多情况下我们不知道变量应该定义为什么类型,比如下面的代码:
#include <iostream>
#include <string>
using namespace std;

class T1
{
public:
    static int get()
    {
        return 10;
    }
};

class T2
{
public:
    static string get()
    {
        return "hello, world";
    }
};

template <class A>
void func(void)
{
    auto val = A::get();
    cout << "val: " << val << endl;
}

int main()
{
    func<T1>();
    func<T2>();
    return 0;
}


在这个例子中定义了泛型函数 func,在函数中调用了类 A 的静态方法 get () ,这个函数的返回值是不能确定的,
如果不使用 auto,就需要再定义一个模板参数,并且在外部调用时手动指定 get 的返回值类型,
具体代码如下:
#include <iostream>
#include <string>
using namespace std;

class T1
{
public:
    static int get()
    {
        return 0;
    }
};

class T2
{
public:
    static string get()
    {
        return "hello, world";
    }
};

template <class A, typename B>        // 添加了模板参数 B
void func(void)
{
    B val = A::get();
    cout << "val: " << val << endl;
}

int main()
{
    func<T1, int>();                  // 手动指定返回值类型 -> int
    func<T2, string>();               // 手动指定返回值类型 -> string
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢打篮球的普通人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值