以有涯随无涯

邵有石的专栏

探索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
阅读更多
个人分类: 技术
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭