探索C++0x: 2. 从初始化表达式自动推断类型(auto)

转载请注明来源:http://blog.csdn.net/thesys/archive/2010/06/02/5641447.aspx

简介

C++0x为了增加自动类型推断的特性,修改了auto这个关键字的含义,这个关键字在现行C++标准中表示生存期为自动,写不写它效果是一样的,几乎就是一废物。因此这次C++0x废物利用,扩展了它的含义,用来表示从初始化表达式自动类型推断了(下面简称自动类型推断)。

最典型的用法如下:
auto x = expression;

x的类型将由等号后面表达式的类型来确定,最明显的好处是,对于某些复杂类型,我们不用再明确写出其类型,例如我们经常遇到的对STL容器遍历时,写的那个迭代器类型。

除了直接声明auto类型的变量外,还可以组合成较复杂的形式,例如:

auto& x = expression; 
auto const& x = expression;
auto* x = expression;
auto const* x= expression;
auto x[100] = expression;
  

说明

auto关键字是一个占位符(placeholder),表示待推断的类型,主要用于变量的初始化表达式,它可以其它的类型修饰符联合使用,包括const, volatile等,例如:

auto score = 100;    // score的类型是int
auto volatile pi = 3.14; // pi的类型是double volatile
auto const* msg = "hello, world"; // msg的类型是char const*
 

自动类型推断,可以应用在全局变量,局部变量,静态局部变量,静态全局变量,类的静态常量成员变量这几个地方。但不能用于函数的参数,模板参数,类的非静态成员变量,类的静态非常量成员变量。(不过GCC4.5的实现有个bug, 可以用于类的静态非常量成员变量,但定义完了却无法访问,报告说找不到这个变量,但又可以对这个变量取typeid,总之是个bug)

使用auto关键字进行自动类型推断,其推断规则完全沿用模板参数类型推断规则,可以简单地认为auto关键字的类型就是函数模板中参数T的类型。例如:

auto x1 = expression1;
template<typename T1>
void func1(T1 t1);
func1(expression1);

auto* x2 = expression2;
template<typename T2>
void func2(T2* t2);
func2(expression2);
第1行auto关键字所代表的类型和第3行中T1所代表的类型完全一致;第6行中的auto关键字代表的类型和第8行中的T2所代表的类型完全一致。
不过函数模板的推导的能力是大于auto关键字的,例如:
 1: template <typename T>
 2: struct X{};
 3:  
 4: template <typename T>
 5: X makeX(T);
 6:  
 7: template <typename T>
 8: void f(X t);
 9:  
 10: void test()
 11: {
 12:     f(makeX(100));             // 正确,对于f函数模板来说,T被推导为int类型
 13:     X<auto> x = makeX(100);    // 错误,auto不能用于模板参数。挺遗憾的,因为支持这个并不难。
 14: }

 

自动类型推断通常只能用于变量的初始化语句,变量的定义后面必须跟有非空非void表达式,而该表达式有两种可选形式:=expression;和(expression),例如下面两行代码是等价的:

auto x = 100;
auto x(100);

对于一个初始化语句中定义多个变量的情况,对于所有变量的定义,所推导出来的auto,必须代表同一个类型,否则就为错。例如:

int a = 1;
auto i = 100, *p = &a; // 正确,auto被推导为int
auto c = 'A', d = 3.14; //错误,无法将auto推导为一致的类型

auto不可用于推导数组类型,如果auto出现在数组变量定义的方括号前面,则编译出错。而且对于等号右边的表达式是数组的情况,等号左边的类型会被推断为指针,例如:

 1: int t1[5];
 2: int t2[5][3];
 3:  
 4: auto x1 = t1;         // x1的类型是int*
 5: auto x2 = t2;         // x2的类型是int(*)[3]
 6: auto* x3 = t2;        // x3的类型是int(*)[3]
 7: auto x4 = {1, 2};     // 对于GCC4.5,x4是std::initializer_list类型,
 8:                       // 对于VC10,报错C2078,还不支持initializer_list
 9:  
 10: auto y1[] = t1;       // 错误,auto不能出现在数组定义的[]前
 11: auto y2[3] = {1,2,3}; // 错误,auto不能出现在数组定义的[]前
 12: auto y3 = {};         // 错误,无法推断出std::initializer_list的类型参数

auto关键字在用于创建对象有点特别,它可以和new一起调用拷贝构造函数来创建一个对象,例如:

 1: auto x1 = new auto(1);        // 正确,x1为int*
 2: int* x2 = new auto(2);        // 正确,x2为int*
 3: auto y1 = auto(1);            // 错误
 4: int y2 = auto(1);             // 错误

auto用于推断有继承关系的类的时候,可能有些令人混淆,例如:

 1: struct Base
 2: {
 3:     virtual void func()
 4:     {
 5:         cout << __LINE__ << endl;
 6:     }
 7: };
 8:  
 9: struct Derived : public Base
 10: {
 11:     virtual void func()
 12:     {
 13:         cout << __LINE__ << endl;
 14:     }
 15: };
 16:  
 17: Derived* dptr = new Derived();
 18: Base* bptr = dptr;
 19: auto x1 = *bptr;     // x1的类型是Base
 20: auto& x2 = *bptr;    // x2的类型是Base&
 21: x1.func();           // 调用Base::func
 22: x2.func();           // 调用Derived::func

你可能感兴趣的:(C++,c,struct,list,gcc,扩展)