当前位置: 首页 > 工具软件 > Auto > 使用案例 >

C++ auto用法及应用详解

蓝夕
2023-12-01


编程时常常需要把表达式的值赋给变量,这就要求声明变量时清楚的知道表达式的类型。然而有些情况是声明的变量的类型我们并不知道,比如在模板编程时。为了解决这个问题,C++11引入了auto类型说明符,用它来让编译器替我们去分析表达式所属的类型。

1.auto的推导规则

这里我首先把推导规则说一下,然后下面会有大量的例子,读者可以结合例子来记住规则。在每个例子后面,我都加了详细的注释,方便读者理解规则。

  • 规则1:声明为auto(不是auto&)的变量,忽视掉初始化表达式的顶层const。即对有const的普通类型(int 、double等)忽视const,对常量指针(顶层const)变为普通指针,对指向常量(底层const)的常量指针(顶层cosnt)变为指向常量的指针(底层const)。
  • 规则2:声明为auto&的变量,保持初始化表达式的顶层const或volatile 属性
  • 规则3:若希望auto推导的是顶层const,加上const,即const auto。

关于顶层和底层const是什么,可参考底层const顶层const到底是什么?

2.auto

1.1 auto例子

int i = 0, &ri = i;

auto a = i; //a为int型变量
auto a1 = ri; //a1为int型变量

auto p = &i;// &i 是一个普通int指针,p是一个整型指针int *
auto p1 = &ri; //同上
const int ci = 2, &rci = ci , ci2 = 9;

auto b = ci;//b为int型变量,因为规则1,b`并不是一个const int型的常量`
auto b1 = rci;//同上
b = 4;b1 = 5;//b和b1的值可以改变

auto cp = &ci;//cp是一个指向常量的指针const int* ,因为&ci对常量对象取地址是底层const,无顶层const属性
cp = &ci2;//cp的指向可以改变

下面看忽视顶层const指针的例子:

int z = 9,z1 = 10;

int* const pz1 = &z;//pz1为int* const(顶层const)
const int* pz2 = &z;//pz2为const int* (底层const)
const int* const pz3= &z;//pz3为const int* const(同时包含底层和顶层const)

auto apz1 = pz1;//apz1为int*
auto apz2 = pz2;//apz2为const int*
auto apz3 = pz3;//apz3为cosnt int*

对于pz1和pz3,它们都有顶层const属性,所以apz1和apz3都会忽略顶层const属性。

这里注意:对常量对象取地址总是看作为一种底层的const,即不是对指针(也就是指向)的常量,而是对指针指向内存中的值是常量。所以上面的&ci是const int*型。

1.2 const auto例子

int i = 0, &ri = i;
const int ci = 2, &rci = ci ;

const auto cb = i; //cb为const int型。因为规则3,cb被提升为const
const auto cb1 = ci; //同上

const auto ca1 = &i;//cal为常量指针。&i本是int*,因为规则3,强行将cal提升为常量指针int *const
const auto ccp = &ci;//本来&ci为const int *,因为规则3,加了const后,提示为const int * const

3.声明为auto引用:auto &

例子:

int i = 0, &ri = i;
const int ci = 2, &rci = ci ;
	
auto & j = i; //j为int &
auto & k = ci; // k为const int &
auto & h = 42; //错误,不能将非常量引用绑定字面值,这是引用&规则决定的

const auto &j2 = i; //j2为const int &,因为规则3,j2被提升为顶层const
const auto &k2 = ci; //k2为const int &
const auto &h2 = 42; //正确,可以为常量绑定字面值 

auto& m =  &i;//Error,无法从“int *”转换为“int *&” ,这是引用&规则决定的
auto& m1 = &ci;// Error,无法从“const int *”转换为“const int *&” ,这是引用&规则决定的
const auto &m2 = &i;//m2为int * const &
const auto &m3 = &ci;//m3为const int * const &

上例子中有3条是错误的,原因是:引用不能绑定表达式的计算结果,除非使用const。并且对于 普通指针而言,它提升到顶层const,只能为常量指针,而不能为指向常量的指针 (原因可参考:为什么无法从“int *”转换为“const int *&”?)。所以后两个都带常量指针属性,最后一个由于本身就是底层的const(即指向常量的指针),所以为指向常量的常量指针。

有关对于指针的引用,我在无法从“int *”转换为“int *&”?详解C++引用(&)使用方法中有详细的介绍,可供大家参考。
有关常量指针和指向常量的指针,我在详解const引用和常量指针、指向常量的指针有一小节详细介绍,可供大家参考。

小结:使用auto &的时候不光需要知道auto&的推到规则,还要明白引用(&)的使用限制。我们首先看的就是&的使用限制。

4.auto在编程时真正的用途

上面我们详细介绍了auto的使用规则,但它仅仅是使用规则而已,在实际编程中我们在明确变量类型情况下,还是使用明确的类型。Auto真正在编程时的实际应用如下:
内容参考至:https://www.cnblogs.com/QG-whz/p/4951177.html

4.1代替冗长复杂的变量声明

我们在使用迭代器时常常会这样操作:

list<int> l1;
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);

for (list<int>::iterator i = l1.begin(); i!= l1.end(); i++){
	cout << i.operator->() << endl;
	cout << *i << endl;
}

这样list<int>::iterator i = l1.begin()的声明迭代器i看起来繁琐冗长,我们实际可以用auto代替:auto i = l1.begin();

4.2定义模板参数时,用于声明依赖模板参数的变量

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

如上所示:我们获取x+y的值,但是x、y都是模板类型,我们无法知道其类型,这时就可以使用auto。

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

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

上面的例子中,返回值依赖于xy的类型,这里我们需要提前查询xy的数据类型,需要用到decltype操作符,它是C++11标准引入的新的运算符,其目的也是解决泛型编程中有些类型由模板参数决定,而难以表示它的问题。
注意:auto在这里的作用也称为返回值占位,它只是为函数返回值占了一个位置

有关decltype,参考:有auto为什么还要decltype ?详解decltype的用法

参考:C++ Primer第5版

以上就是auto的详细介绍。如果有疑问,欢迎评论区下方留言;本人水平有限 ,如有错误,也欢迎在评论区下方批评指正。若是喜欢本文,就帮忙点赞吧!

 类似资料: