C++ 深入理解 auto 关键字

auto类型变量——根据初始值推断真实的数据类型。

【为什么auto】
在开发实践中,有时候我们并不能非常容易地确定一个变量应该具有的数据类型。比如,将某个复杂表达式作为初始值赋值给一个新定义的变量时,我们往往很难确定这个表达式的数据类型,从而无法确定变量应有的数据类型。为了解决这个问题,C++11为我们提供了auto关键字,使用它作为某个变量定义的数据类型,编译器会根据这个变量的初始值,自动推断出这个变量合理的数据类型而无需我们人为指定。

【auto概念详解】

auto关键字——根据初始值推断真实的数据类型。

auto存储类型说明

auto存储类型说明符声明了一个自动变量,auto对象和变量被存储在栈中,它的生命周期仅存在于它的声明所在的块(block)中,即一个只在块运行时有效的变量。一个auto变量仅在声明它的块内是可见的。auto对象和变量对外部模块都是不可见的。auto变量的声明能包含初始化。因为有auto存储类型的变量并不自动的初始化,应该在声明时显式的初始化它们,或在同一个块内赋给它们初始值。未初始化的auto变量的值是未定义的。


【auto代码使用示例】

auto x = 7;      // 使用整数7对变量x进行初始化,x被推断为int类型
auto y = 1.982;  // 使用浮点数1.982对变量y进行初始化,y被推断为double类型
Handler GetHandler();
// 使用GetHandler()函数的返回值对变量handler进行初始化
// handler被推断为Handler类型
auto handler = GetHandler();
这里我们在定义变量x的时候,并没有指定其具体的数据类型,而是使用auto做为代替。这样,编译器在编译这段代码时,会根据7这个初始值自动推断x的实际数据类型为int。同样的道理,使用浮点数1.982进行初始化的变量y会被编译器自动推断为double类型;而最后的一个变量handler会被初始化为GetHandler()函数的返回值类型Handler。虽然auto关键字会根据初始值自动推断变量的数据类型,但是,它的使用并不需要花费额外的编译时间。

实际上,可以把auto关键字看成是一个变量定义中的数据类型占位符,它占据了原来应该是具体数据类型的位置。而在编译的时候,编译器会根据这个变量的初始值,推断出这个变量应有的具体数据类型,然后替换掉auto关键字,就成为一个普通的带有具体数据类型的变量定义了。用auto关键字定义变量的形式跟一般的定义变量的形式并无二异,唯一的差别之处在于,用auto关键字定义变量时,变量必须有初始值:

auto 变量名 = 初始值表达式;  // 赋值形式
// 或
auto 变量名{初始值表达式}; // 初始化列表形式
这样,这个初始值表达式计算结果的数据类型将被编译器推断为变量的数据类型。
template 
// 数据类型vector之后的“&”符号,表示其后所定义的变量是一个引用
// 引用是C++中一种访问数据的特殊方式,在稍后的7.1小节中我们将详细介绍
void printall(const vector& v)
{
    // 根据v.begin()的返回值类型自动推断变量it的数据类型
    for (auto it = v.begin(); it != v.end(); ++it)
        cout << *it << endl;
}
为了表示同样的意义,如果没有auto关键字帮忙,我们不得不写成下面这种繁琐的形式:
template 
void printall(const vector& v)
{
    for (typename vector::const_iterator it = v.begin();
        it != v.end(); ++it)
        cout << *it << endl;
}
除了简化代码之外,auto关键字有时候甚至能够帮助我们完成一些在C++11之前不可能完成的任务,成为一种必需。比如,在模板函数中,当一个变量的数据类型依赖于模板参数时,如果不使用auto关键字,将根本无法确定变量的数据类型,因为我们根本无法提前预知用户使用何种数据类型作为模板参数来调用这个模板函数,从而也就无法确定这个变量的数据类型。但是使用auto关键字之后,一切难题都将迎刃而解。例如:
template 
void mul(const T& t,const U& u)
{
    // ...
    // 用auto关键字做数据类型,编译器将根据u和t的实际数据类型,
    // 自动推断变量tmp的数据类型
    auto tmp = t*u;


    // ...
}
在这里,变量tmp的数据类型应该与模板参数T和U相乘结果的数据类型相同,也就是依赖于T和U的数据类型。对于程序员来说,在编写这个模板函数的时候,模板参数T和U的类型尚未确定,这样变量tmp的类型也就无法确定。所以,我们用auto关键字作为占位符,占据数据类型的位置,而真正的数据类型,则留待编译器在最终编译的时候,根据具体给定的模板参数T和U的类型而推断得到。这样,就把一件原来不可能的事情变成了可能。
使用auto关键字,可以根据变量的初始值自动推断其数据类型,这样就极大地方便了复杂数据类型变量的定义。但是,这种方式好是好,却有一个缺点,那就是每次推断得到的数据类型只能在定义变量的时候使用一次,无法保留下来继续使用。好不容易推断得到的数据类型只能使用一次,这就显得有点不够低碳环保了。而有时候,我们也需要这个推断得到的数据能够保留下来,从而可以重复使用以定义相同类型的多个变量。为了弥补这个缺点,C++11还提供了一个decltype关键字。decltype(表达式)是这个表达式的推断数据类型(declared type),也就是这个表达式计算结果的数据类型。而typedef则是将这个数据类型定义为用户自定义的数据类型,换句话说,也就是为这个推断数据类型取一个名字,从而可以把它作为一个新的数据类型,用在定义变量、创建对象等任何需要数据类型的地方。例如,我们可以用decltype关键字改写上面的例子:

template 
void mul(const T& t,const U& u)
{
    // ...
    // 用decltype得到t*u的数据类型,
    // 并用typedef关键字将其定义成一个新的数据类型M
    typedef decltype(t*u) M;
    // 用这个新的数据类型M定义指针变量(表示变量或函数地址的变量),创建M类型对象
    M* tmp = nullptr;
    tmp = new M;     // ...
}

auto和decltype的作用有些相似,都可以推断某个表达式的具体数据类型。但是,两者的使用还是稍有差别。如果我们仅仅是想根据初始值确定一个变量合适的数据类型,那么auto是最佳人选。而只有当我们需要推断某个表达式的数据类型,并将其作为一种新的数据类型重复使用(比如,定义多个相同类型变量)或者单独使用(比如,作为函数的返回值类型)时,我们才真正需要用到decltype。


【auto注意事项】
什么时候不应该用auto:
1.需要明确的告诉阅读者类型的时候。(代码可读性问题)
2.要在多个编译器下面编译的时候。(并非每个编译器都支持auto)
3.当你要定义string而用const char*初始化的时候(以及类似的情况)。

4.过去的代码中已经使用了auto,但是并非自动推断类型的意义的时候如:auto int a = 100;如果开启自动推断那么这是错误的语法。

【另】

这样的代码是不能通过编译的:

auto a;

因为auto关键字要求必须有初始值。error C3531: “a”: 类型包含“auto”的符号必须具有初始值设定项。

【参考目录】

http://blog.csdn.net/nihaoCPP/article/details/39551233

http://blog.csdn.net/u012512762/article/details/40736817

http://blog.csdn.net/mastek/article/details/1888273

你可能感兴趣的:(C++/C,语法技巧,小贴士,auto,register,static,关键字,数据类型)