C++98auto
早在C++98标准中就存在了auto关键字,那时候的作用是让变量变成自动变量,拥有自动的生命周期,但是临时变量在声明的时候本身就是自动生命周期了,所以这显得很多余。
int a =10 ; //拥有自动生命期
auto int b = 20 ;//拥有自动生命期
static int c = 30 ;//延长了生命期
取而代之,C++11就删除了原来的用法,改为了自动推导变量类型。
C++11auto
auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型,类似的关键字还有decltype。举个例子:
#include <iostream>
using namespace std;
int main()
{
int a = 10;
auto au_a = a;
cout << typeid(au_a).name() << endl;
system("pause");
return 0;
}
程序的运行结果输出了
int
请按任意键继续. . .
auto的自动类型推断发生在编译期,所以使用auto并不会造成程序运行时效率的降低。而是否会造成编译期的时间消耗,我认为是不会的,在未使用auto时,编译器也需要得知右操作数的类型,再与左操作数的类型进行比较,检查是否可以发生相应的转化,是否需要进行隐式类型转换。
auto的用法
上面举的这个例子很简单,在真正编程的时候也不建议这样来使用auto,直接写出变量的类型更加清晰易懂。下面列举auto关键字的正确用法。
想象一下在没有auto的时候,我们操作标准库时经常需要这样:
#include<string>
#include<vector>
int main()
{
std::vector<std::string> vs;
for (std::vector<std::string>::iterator i = vs.begin(); i != vs.end(); i++)
{
//...
}
}
这样看代码写代码实在是太过于冗长复杂,不好看。
使用auto能简化代码:
#include<string>
#include<vector>
int main()
{
std::vector<std::string> vs;
for (auto i = vs.begin(); i != vs.end(); i++)
{
//..
}
}
for循环中的i将在编译时自动推导其类型,而不用我们显式去定义那长长的一串。
在定义模板函数时,用于声明依赖模板参数的变量类型。
template <typename _Tx,typename _Ty>
void Multiply(_Tx x, _Ty y)
{
auto v = x*y;//此处的v我们不能明确类型就用auto,让其自动编译推导
std::cout << v;
}
模板函数依赖于模板参数的返回值
template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty)
{
return x*y;
}
decltype操作符用于查询表达式的数据类型,也是C++11标准引入的新的运算符,其目的也是解决泛型编程中有些类型由模板参数决定,而难以表示它的问题 。
auto在这里的作用也称为返回值占位,它只是为函数返回值占了一个位置,真正的返回值类型是后面的decltype(__Tx* _Ty)。为何要将返回值后置呢?如果没有后置,则函数声明时为
decltype(_Tx*_Ty)multiply(_Tx x, _Ty y)
而此时 _Tx , _Ty还没声明呢,编译无法通过。
注意事项
-
auto 变量必须在定义时初始化,这类似于const关键字和引用&。(因为不初始化就没有办法推导变量类型)
-
定义在一个auto序列的变量必须始终推导成同一类型。例如:
auto a4 = 10, a5 = 20, a6 = 30;//正确
auto b4 = 10, b5 = 20.0, b6 = 'a';//错误,没有推导为同一类型
使用auto关键字做类型自动推导时,要注意以下规则:
- 如果初始化表达式是引用,则会自动去除引用语义。必须使用auto &进行推导
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int &b = a;
auto c = b;//c的类型为int而非int&(去除引用)
auto &d = b;//此时c的类型才为int&
c = 100;//a =10;
cout << "after change value of c, a = " << a << endl;
d = 1000;//a =1000;
cout << "after change value of d, a = " << a << endl;
system("pause");
return 0;
}
after change value of c, a = 10
after change value of d, a = 1000
请按任意键继续. . .
- 如果初始化表达式为const或volatile(或者两者兼有),则除去const/volatile语义。
#include <iostream>
using namespace std;
int main()
{
const int a1 = 10;
auto b1 = a1;//b1的类型为int 而不是 const int(自动去除了const)
b1 = 100;//改变值不会报错
const auto c1 = a1;
c1 = 100;//会报错
system("pause");
return 0;
}
- 如果auto关键字带上&号,则不去除const语意。
#include <iostream>
using namespace std;
int main()
{
const int a2 = 10;
auto &b2 = a2;//因为auto带上&,故不去除const
b2 = 10; //b2的类型为const int,会报错,准确的来说是b2是a2的引用,类型和a2一样
system("pause");
return 0;
}
- 初始化表达式为数组时,auto关键字推导类型为指针。
#include <iostream>
using namespace std;
int main()
{
int a[3] = { 1, 2, 3 };
auto b = a;
cout << typeid(b).name() << endl;//类型为int *
cout << b[0] << endl;//也可以像数组一样通过下标操作
system("pause");
return 0;
}
int *
1
请按任意键继续. . .
- 若表达式为数组且auto带上&,则推导类型为数组类型。
#include <iostream>
using namespace std;
int main()
{
int a[3] = { 1, 2, 3 };
auto &b = a;
cout << typeid(b).name() << endl;
cout << b[0] << endl;
system("pause");
return 0;
}
int [3]
1
请按任意键继续. . .
- 函数或者模板参数不能被声明为auto
void func(auto a) //错误
{
//...
}
- 时刻要注意auto并不是一个真正的类型。
auto仅仅是一个占位符,它并不是一个真正的类型,不能使用一些以类型为操作数的操作符,如sizeof或者typeid。
cout << sizeof(auto) << endl;//错误
cout << typeid(auto).name() << endl;//错误
能被声明为auto
void func(auto a) //错误
{
//...
}
- 时刻要注意auto并不是一个真正的类型。
auto仅仅是一个占位符,它并不是一个真正的类型,不能使用一些以类型为操作数的操作符,如sizeof或者typeid。
cout << sizeof(auto) << endl;//错误
cout << typeid(auto).name() << endl;//错误