上一篇:《深入理解C++11》笔记-模板的别名、模板的SFINEA规则
本篇开始介绍第四章的内容:auto类型。
auto类型推导
我们在使用C++的时候,变量都需要声明类型:int、char等等,这就是所谓的静态类型语言。而有些语言则不同,他们不需要对变量声明明确的类型,例如Python、JS等,也就是所谓的动态类型语言。静态类型和动态类型的区别其实主要在于对变量进行类型检查的时间点:静态类型的类型检查主要在编译期,而动态类型的类型检查主要在运行时,而运行时检查类型的实现依赖于类型推导。
C++11中重新定义了auto关键字,实现了类型推导。auto在早期的C/C++标准中的意义是修饰变量,让变量成为自动存储期的局部变量,然而大家都很少用,因为局部变量不用任何修饰也拥有自动存储期。所以在C++11中就哪来用做新的类型指示符,作用类似于JS的var。
double func() { return 1.0; }
struct _s_stuct {
int i;
}stu;
int main()
{
auto x = 1; // int类型
auto y = func(); // double类型
auto stu1 = stu; // struct _s_stuct类型
auto z; // 编译失败,无法推导出类型
return 0;
}
auto的优势
由于C++的名字空间、模板等特性,有时候变量类型很复杂,auto的一个优势就是简化一些代码。例如:
std::map<std::string, std::string> mapString;
// 通常的写法
std::map<std::string, std::string>::const_iterator citor = mapString.begin();
while (citor != mapString.end())
{
++citor;
}
// 使用auto之后
for (auto i = mapString.begin(); i != mapString.end(); ++i)
{
}
auto还能更好的支持模板类型推导:
template<typename T1, typename T2>
auto sum(T1& a, T2& b)
{
return a + b;
}
int main()
{
int a = 1;
long b = 2;
auto s1 = sum<int, long>(a, b);
std::cout << typeid(s1).name() << std::endl; // long
float c = 1.0f;
float d = 2.0f;
auto s2 = sum<float, float>(c, d);
std::cout << typeid(s2).name() << std::endl; // float
return 0;
}
auto的使用细则
auto的指针和引用规则:
int func1() { return 1; }
int& func2() { int a = 1; return a; }
int main()
{
int x = 1;
int* y = &x;
auto* a = &x; // int*类型
auto& b = x; // int&类型
auto c = y; // int*类型
auto* d = y; // int*类型
auto e = func2(); // int类型
auto* f = func1(); // 编译失败,指针不能指向临时变量
auto& g = func1(); // 编译失败,非const引用不能绑定临时变量
auto h = func2(); // int类型
auto& i = func2(); // int&类型
}
auto的const和volatile规则:
int num = 1;
const auto a = num; // const int类型
const auto& b = num; // const int&类型
volatile auto* c = # // volatile int*类型
auto d = a; // int类型,auto无法带走const属性
auto& e = a; // const int类型,auto引用可以
auto f = c; // int*类型,auto无法带走volatile属性
auto& g = c; // volatile int*类型,auto引用可以
auto不能使用的情况:
void func(auto x) {} // auto不能作为函数参数
struct stu {
auto var = 10; // 非静态auto类型不能成员变量
static const auto var = 10; // 编译通过
};
int main()
{
char x[3] = { 0 };
auto y = x;
auto z[3] = x; // auto不能作为数组类型
std::vector<auto> v = { 1 }; // auto不能作为模板实例化类型
return 0;
}