outo简介
在早期C/C++中auto的含义是:使用auto 修饰的变量,是具有自动存储器的局部变量,但即使不加这个关键词,默认就是具有自动存储器的局部变量,所以说这个词几乎没有任何卵用。
C++11 中,标准委员会赋予了 auto
全新的含义即: auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
int TestAuto()
{
return 10;
}
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = TestAuto();
//typeid(b).name()用于显示对用变量的类型,此函数返回一个字符串
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
return 0;
}
【注意】
使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。
使用细则
-
auto的指针和引用:
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&int main() { int x = 10; auto a = &x; auto* b = &x; auto& c = x; cout << typeid(a).name() << endl; cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; *a = 20; *b = 30; c = 40; return 0; }
-
在同一行定义多个变量
当在同一行定义多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为auto其实就是占位,之后会根据后面的类型推导一个出来,但是如果后面放了两种不同类型变量,必崩好吧。void TestAuto() { auto a = 1, b = 2; auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同 }
outo不能推导的场景
-
auto不能作为函数的参数或返回值
auto TestAuto(auto a) { return 3; }
此处的代码编译失败,因为编译器无法对 a 的实际类型进行推导;
即使说这里的3作为是返回值可以被推导为int,但是当初在规定auto语法的时候就杜绝了让它做参数或返回值,防止了用户对 auto 的滥用,试想如果一个函数都是 auto 你还能直观判断到底传什么参数,用什么接受返回值吗? -
auto不能直接用来声明数组
void TestAuto() { int a[] = { 1,2,3 }; auto b[] = { 4,5,6 }; }
-
为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
实际应用中的outo
-
自动推导较长类型
看如下场景:
#include <iostream> #include <map> #include <string> using namespace std; int main() { std::map<std::string, std::string> dict; dict["sort"] = "排序"; dict["string"] = "字符串"; std::map<std::string, std::string>::iterator it = dict.begin();//it前面都是它的类型 }
看不看的的懂不重要,知道
std::map<std::string, std::string>::iterator
是个变量名就行,而且他很长,这时候就可以用auto替换:
-
结合范围for使用:
decltype
auto是根据右侧的返回值进行推导
关键字decltype与其相似,将变量的类型声明为括号内表达式指定的类型。
与typeid的使用方法相同,但typeid是获取类型的字符串,而decltype获取后,自己就是那个类型
如:decltype(1+1) num;
完全等同于int num;
// decltype的一些使用使用场景
template<class T1, class T2>
void F(T1 t1, T2 t2)
{
decltype(t1 * t2) ret;
cout << typeid(ret).name() << endl;
}
int main()
{
const int x = 1;
double y = 2.2;
decltype(x * y) ret; // ret的类型是double
decltype(&x) p; // p的类型是int*
cout << typeid(ret).name() << endl;
cout << typeid(p).name() << endl;
F(1, 'a');
return 0;
}
上面的案例有些一般不会在实际应用中出现
declytype的一般用于推导lambda表达式的类型后用于模板参数
例如,priority_queue
、map、unordered_map这些类模板可以通过向模板参数中传入一些仿函数用于比较,或者作为哈希函数,此时,我们就可以定义一个lambda表达式定义比较方法,模板参数需要传入一个类型,而不是lambda这种变量,此时就可以用declype推到出lambda的类型后传入。