C++11新特性:自动类型推断和类型获取

简介: 声明:本文是在Alex Allain的文章http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html的基础上写成的。

声明:本文是在Alex Allain的文章http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html的基础上写成的。

加入了很多个人的理解,不是翻译。

 

转载请注明出处 http://blog.csdn.net/srzhz/article/details/7934483

 

自动类型推断

当编译器能够在一个变量的声明时候就推断出它的类型,那么你就能够用auto关键字来作为他们的类型:

 

[cpp]  view plain copy
 
  1. auto x = 1;  


编译器当然知道x是integer类型的。所以你就不用int了。接触过泛型编程或者API编程的人大概可以猜出自动类型推断是做什么用的了:帮你省去大量冗长的类型声明语句。

 

比如下面这个例子:

在原来的C++中,你要想使用vector的迭代器得这么写:

[cpp]  view plain copy
 
  1. vector<int> vec;  
  2. vector<int>::iterator itr = vec.iterator();  

看起来就很不爽。现在你可以这么写了:

 

 

[cpp]  view plain copy
 
  1. vector<int> vec;  
  2. auto itr = vec.iterator();  

果断简洁多了吧。假如说自动类型推断只有这样的用法的话那未免也太naive了。在很多情况下它还能提供更深层次的便利。

 

比如说有这样的代码:

 

[cpp]  view plain copy
 
  1. template <typename BuiltType, typename Builder>  
  2. void  
  3. makeAndProcessObject (const Builder& builder)  
  4. {  
  5.     BuiltType val = builder.makeObject();  
  6.     // do stuff with val  
  7. }  

这个函数的功能是要使用builder的makeObject产生的实例来进行某些操作。但是现在引入了泛型编程。builder的类型不同,那么makeObject返回的类型也不同,那么我们这里就得引入两个泛型。看起来很复杂是吧,所以这里就可以使用自动类型推断来简化操作:

[cpp]  view plain copy
 
  1. template <typename Builder>  
  2. void  
  3. makeAndProcessObject (const Builder& builder)  
  4. {  
  5.     auto val = builder.makeObject();  
  6.     // do stuff with val  
  7. }  


因为在得之builder的类型之后,编译器就已经能知道makeObject的返回值类型了。所以我们能够让编译器自动去推断val的类型。这样一来就省去了一个泛型。

 

你以为自动类型推断只有这样的用法?那也太naive了。C++11还允许对函数的返回值进行类型推断

 

新的返回值语法和类型获取(Decltype)语句

 
在原来,我们声明一个函数都是这样的:
[cpp]  view plain copy
 
  1. int temp(int a, double b);  

前面那个int是函数的返回值类型,temp是函数名,int a, double b是参数列表。

现在你可以将函数返回值类型移到到参数列表之后来定义:

 

[cpp]  view plain copy
 
  1. auto temp(int a, double b) -> int;  


后置返回值类型可以有很多用处。比如有下列的类定义:

 

 

[cpp]  view plain copy
 
  1. class Person  
  2. {  
  3. public:  
  4.     enum PersonType { ADULT, CHILD, SENIOR };  
  5.     void setPersonType (PersonType person_type);  
  6.     PersonType getPersonType ();  
  7. private:  
  8.     PersonType _person_type;  
  9. };  


那么在定义getPersonType函数的时候我们得这么写:

 

 

[cpp]  view plain copy
 
  1. Person::PersonType Person::getPersonType ()  
  2. {  
  3.     return _person_type;  
  4. }  


因为函数所在的类Person是声明在函数返回值之后的,所以在写返回值的时候编译器并不知道这个函数是在哪个类里面。由于PersonTYpe是Person类的内部声明的枚举,所以在看到PersonType的时候,编译器是找不到这个类型的。所以你就得在PersonTYpe前面加上Person::,告诉编译器这个类型是属于Person的。这看起来有点麻烦是吧。当你使用新的返回值语法的时候呢就可以这么写:

 

 

[cpp]  view plain copy
 
  1. auto Person::getPersonType () -> PersonType  
  2. {  
  3.     return _person_type;  
  4. }  


因为这次编译器看到返回值类型PersonType的时候已经知道这个函数属于类Person。所以它会到Person类中去找到这个枚举类型。

 

 

当然上述应用只能说是一个奇技淫巧而已。并没有帮我们多大的忙(代码甚至都没有变短)。所以还得引入C++11的另一个功能。

 

类型获取(Decltype)

 
既然编译器能够推断一个变量的类型,那么我们在代码中就应该能显示地获得一个变量的类型信息。所以C++介绍了另一个功能:decltype。(实在是不知道这个词该怎么翻译,姑且称之为类型获取)。
 
[cpp]  view plain copy
 
  1. int x = 3;  
  2. decltype(x) y = x; // same thing as auto y = x;  

上述代码就使用了类型获取功能。和函数返回值后置语法结合起来,可以有如下应用:
[cpp]  view plain copy
 
  1. template <typename Builder>  
  2. auto  
  3. makeAndProcessObject (const Builder& builder) -> decltype( builder.makeObject() )  
  4. {  
  5.     auto val = builder.makeObject();  
  6.     // do stuff with val  
  7.     return val;  
  8. }  

前面的例子中这个函数的返回值是void,所以不需要为返回值引入泛型。如果返回值是makeObject的返回值的话,那么这个函数就得引入两个泛型。现在又了类型获取功能,我们就能在返回值中自动推断makeObject的类型了。所以decltype确实为我们提供了很大的便利。
 
这个功能非常重要,在很多时候,尤其是引入了泛型编程的时候,你可能记不住一个变量的类型或者类型太过复杂以至于写不出来。你就要灵活使用decltype来获取这个变量的类型。

自动类型推断在Lambda表达式(匿名函数)中的作用

请参考http://blog.csdn.net/srzhz/article/details/7934652

目录
相关文章
|
25天前
|
编译器 程序员 定位技术
C++ 20新特性之Concepts
在C++ 20之前,我们在编写泛型代码时,模板参数的约束往往通过复杂的SFINAE(Substitution Failure Is Not An Error)策略或繁琐的Traits类来实现。这不仅难以阅读,也非常容易出错,导致很多程序员在提及泛型编程时,总是心有余悸、脊背发凉。 在没有引入Concepts之前,我们只能依靠经验和技巧来解读编译器给出的错误信息,很容易陷入“类型迷路”。这就好比在没有GPS导航的年代,我们依靠复杂的地图和模糊的方向指示去一个陌生的地点,很容易迷路。而Concepts的引入,就像是给C++的模板系统安装了一个GPS导航仪
100 59
|
1月前
|
存储 编译器 程序员
C++类型参数化
【10月更文挑战第1天】在 C++ 中,模板是实现类型参数化的主要工具,用于编写能处理多种数据类型的代码。模板分为函数模板和类模板。函数模板以 `template` 关键字定义,允许使用任意类型参数 `T`,并在调用时自动推导具体类型。类模板则定义泛型类,如动态数组,可在实例化时指定具体类型。模板还支持特化,为特定类型提供定制实现。模板在编译时实例化,需放置在头文件中以确保编译器可见。
30 11
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(三)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(二)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(一)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
18天前
|
C++
C++ 20新特性之结构化绑定
在C++ 20出现之前,当我们需要访问一个结构体或类的多个成员时,通常使用.或->操作符。对于复杂的数据结构,这种访问方式往往会显得冗长,也难以理解。C++ 20中引入的结构化绑定允许我们直接从一个聚合类型(比如:tuple、struct、class等)中提取出多个成员,并为它们分别命名。这一特性大大简化了对复杂数据结构的访问方式,使代码更加清晰、易读。
30 0
|
2月前
|
编译器 C++ 计算机视觉
C++ 11新特性之完美转发
C++ 11新特性之完美转发
45 4
|
2月前
|
编译器 C++ 容器
C++ 11新特性之语法甜点2
C++ 11新特性之语法甜点2
29 1
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析继承机制(三)
【C++】面向对象编程的三大特性:深入解析继承机制