C++ 11新特性的用法之auto

一、静态类型,动态类型和类型推导

在编程语言分类中,C/C++C常常被认为是静态类型的语言。而有的编程语言则号称是“动态类型”的,比如python。通常情况下,“静”和“动”的区别是非常直观的。我们看看下面这段简单的python代码:

  name=‘world\n’
  print 'hello, ' %name

这段代码中python中的一个hellowworld的实现。这就是编程语言中的“动态类型”,在运行时来进行类型检查,而C++中类型检查是在编译阶段。动态类型语言能做到在运行时决定类型,主要归功于一技术,这技术是类型推导。

事实上,类型推导也可以用于静态类型语言中。比如上面的python代码中,如果按照C/C++程序员的思考方式,world\n表达式应该可以返回一个临时的字符串,所以即使name没有进行声明,我们也能轻松低推导出name的类型应该是一个字符串类型。在C++11中,这个想法得到了实现。C++11中类型推导的实现之一就是重定义auto关键字,另一个实现是decltype。

我们可以使用C++11方式来书写刚才的python的代码

#include <iostream>
using namespace std;
int main()
{
  auto name=‘world\n’
  cout<<"hello   "<<name<<endl;

}

这里使用auto关键字来要求编译器对变量name的类型进行了自动推导。这里编译器根据它的初始化表达式的类型,推导出name的类型为char*。事实上,atuo关键字在早期的C/C++标准中有着完全不同的含义。声明时使用auto修饰的变量,按照早期C/C++标准的解释,是具有自动存储期的局部变量。不过系那是情况是该关键字几乎无人使用,因为一般函数内没有声明为static的变量总是具有自动存储期的局部变量。auto声明变量的类型必须又编译器在编译时期推导而得。

通过以下例子来了解以下auto类型推导的基本用法

#include <iostream>
using namespace std;
int main()
{
     double foo();
	 auto x=1;
	 auto y=foo();
	 struct m
	 {
	     int i;
	 }str;
	 auto str1=str;
	 auto z;
	 z=x;
}

以上变量x被初始化为1,因为字面变量1的类型是const int,所以编译器推导出x的类型应该为int(这里const类型限制符被去掉了,后面会解释)。同理在变量y的定义中,auto类型的y被推导为double类型;而在auto str1的定义中,其类型被推导为struct m。这里的z,使用auto关键字来声明,但是不立即对其进行定义,此时编译器则会报错。这跟通过其他关键字(除去引用类型的关键字)先声明后定义的变量的使用规则是不同的。auto声明的变量必须被初始化,以使编译器能够从其初始化表达式中推导出其类型。这个意义上,auto并非一种类型声明,而是一个类型声明时的“占位符”,编译器在便已是亲会将suto替代为变量实际的类型。

二、auto的优势

1.直观地,auto推导的一个最大的优势在于拥有初始化表达式的复杂类型变量声明时简化代码。由于C++的发展,变量类型变得越来越复杂。但是很多时候,名字空间、模板成为类型的一部分,导致了程序员在使用库的时候如履薄冰。

#include <string>
#include <vector>
void loopover(std::vector<std::string>&vs)
{
    std::vector<std::string>::iterator i=vs.begin();
	for(;i<vs.end();i++)
	{

	}

}
 使用std::vector<std::string>::iterator 来定义i是C++常用的良好的习惯,但是这样长的声明带来了代码可读性的困难,因此引入auto,使代码可读性增加。并且使用STL将会变得更加容易
<pre name="code" class="cpp">#include <string>
#include <vector>
void loopover(std::vector<std::string>&vs)
{
	for(  auto i=vs.begin();;i<vs.end();i++)
	{

	}

}

2.可以避免类型声明时的麻烦而且避免类型声明时的错误。事实上,在C/C++中,存在着很多隐式或者是用户自定义类型的转换规则(比如整型与字符型进行加法运算后,表达式返回整型,这是一条隐式规则)。这些规则并非容易记忆,尤其是在用户自定义很多操作符以后,这个时候auto就有用户之地了。看一下例子

class PI
{
   public :
          double operator*(float v)
		  {
		     return (double)val*v;
		  }
          const float val=3.1415927f;
}
int main()
{
          float radius=1.7e10;
	  PI pi;
	  auto circumference =2*(pi*radius);
}

上面定义了一个float类型的变量radius(半径)以及一个自定义类型PI的变量pi,在计算周长的时候,使用auto类型来定义变量circumference。这里PI在于float类型数据相乘时,其返回值为double。而PI得定义可能是在其他的地方(头文件里),main函数的程序可能就不知道PI的作者为了避免数据上溢或者是精度上的降低而返回了double类型的浮点数。因此main函数程序员如果使用float类型声明circumference,就可能会享受不了PI作者细心设计带来的好处。反之,将circumference声明为auto,则毫无问题,因为编译器已经做了最好的选择。

但是auto不能解决所有的精度问题。下面例子

#include <iostream>
using namespace std;
int main()
{
   unsigned int a=4294967295;//最大的unsigned int值
   unsigned int b=1;
   auto c=a+b;
   cout<<"a="<<a<<endl;
   cout<<"b="<<b<<endl;
   cout<<"c="<<c<<endl;
}

上面代码中,程序员希望通过声明变量c为auto就能解决a+b溢出的问题。而实际上由于a+b返回的依然是unsigned int的值,姑且c的类型依然被推导为unsigned int,auto并不能帮上忙。这个跟动态类型语言中数据hi自动进行拓展的特性还是不一样的。

3.在C++中其“自适应”性能够在一定程度上支持泛型的编程。

回到上面class PI的例子,这里假设PI的作者改动了PI的定义,比如讲operator*返回值变为long  double,此时,main函数并不需要修改,因为auto会“自适应”新的类型。同理,对于不同平台上的二代马维护,auto也会带来一些“泛型”的好处。这里我们一strlen函数为例,在32位编译环境下,strlen返回的为一个4字节的整型,在64位的编译环境下,strlen会返回一个8字节的整型。即使系统库中<cstring>为其提供了size_t类型来支持多平台间的代码共享支持,但是使用auto关键字我们同样可以达到代码跨平台的效果。

auto var=strlen("hello world").

由于size_t的适用性范围往往局限于<cstring>中定义的函数,auto的适用范围明显更为广泛。

当auto应用于模板的定义中,其"自适应"性会得到更加充分的体现。我们可以看看以下例子

template<typename T1,typename T2>
double Sum(T1&t1,T2&t2)
{
        auto a=t1+t2;
	return a;
}
int main()
{
        int a=3;
	long b=5;
	float c=1.0f;
	float d=2.3f;
	auto e=Sum<int,long>(a,b); //e的类型被推导为long
	auto f=Sum<float,float>(c,d);//s的类型被推导为float
}

上面中Sum模板函数接受两个参数。由于T1,T2要在模板实例化时才能确定,所以Sum中将变量s的类型声明为auto的。在函数main中我们将模板实例化时。Sum<int,long>中的s变量会被推导为long类型,而Sum<float,float>中的s变量则会被推导为float。可以看到,auto与模板一起使用时,其“自适应”特性能够加强C++中泛型的能力。

三、auto的使用注意细节

①我们可以使用valatile,pointer(*),reference(&),rvalue reference(&&) 来修饰auto

auto k = 5;
auto* pK = new auto(k);
auto** ppK = new auto(&k);
const auto n = 6;

②用auto声明的变量必须初始化

auto m; // m should be intialized  

③auto不能与其他类型组合连用

auto int p; // 这是旧auto的做法。

④函数和模板参数不能被声明为auto

void MyFunction(auto parameter){} // no auto as method argument
template<auto T> // utter nonsense - not allowed
void Fun(T t){}

⑤定义在堆上的变量,使用了auto的表达式必须被初始化

int* p = new auto(0); //fine
int* pp = new auto(); // should be initialized
auto x = new auto(); // Hmmm ... no intializer
auto* y = new auto(9); // Fine. Here y is a int*
auto z = new auto(9); //Fine. Here z is a int* (It is not just an int)

⑥以为auto是一个占位符,并不是一个他自己的类型,因此不能用于类型转换或其他一些操作,如sizeof和typeid

int value = 123;
auto x2 = (auto)value; // no casting using auto
auto x3 = static_cast<auto>(value); // same as above 

⑦定义在一个auto序列的变量必须始终推导成同一类型

auto x1 = 5, x2 = 5.0, x3='r';  // This is too much....we cannot combine like this

⑧auto不能自动推导成CV-qualifiers(constant
& volatile qualifiers),除非被声明为引用类型

const int i = 99;
auto j = i;       // j is int, rather than const int
j = 100           // Fine. As j is not constant
// Now let us try to have reference
auto& k = i;      // Now k is const int&
k = 100;          // Error. k is constant
// Similarly with volatile qualifer

⑨auto会退化成指向数组的指针,除非被声明为引用

int a[9];
auto j = a;
cout<<typeid(j).name()<<endl; // This will print int*
auto& k = a;
cout<<typeid(k).name()<<endl; // This will print int [9]
时间: 2024-10-11 10:17:47

C++ 11新特性的用法之auto的相关文章

c++11 新特性之 auto关键字

C++11是对目前C++语言的扩展和修正.C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto.decltype,和模板的大量改进. g++编译c++11命令加上 -std=c++11 C++11中引入auto第一种作用是为了自动类型推导 auto的自动类型推导,用于从初始化表达式中推断出变量的数据类型.通过auto的自动类型推导,可以简化我们的编程工作 auto实际上实在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响另外,似乎auto并不会影响编译速度,

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

声明:本文是在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关键字来作为他们的类型: [c

C++:C++11新特性超详细版(1)

前言: 虽然目前没有编译器能够完全实现C++11,但这并不意味着我们不需要了解,学习它.深入学习C++11,你会发现这根本就是一门新的语言,它解决了c++98中许多遗留下来的问题.早晚会有一天,C++11便会普及大部分编译器.因此,提早做些准备也是应该的. 在此我想做一个关于C++11的专题,将C++11的新特性进行一一讲解,以通俗易懂的语言及例子帮助读者入门C++11.本文便是C++11新特性超详细版系列文章的第一篇, 即C++:[C++11]新特性超详细版(1). 不过我要强调的是,这些文章

逐个使用C++11新特性

C++11 auto & decltype auto:根据变量初始值来推导变量类型,并用右值初始化变量. decltype:从表达式推导出类型,并将变量定义为该类型,但不用表达式的值初始化该变量. 这里要注意下:decltype(i)--是i的类型,而decltype((i))就是引用了.就像上面例子中的x 就是int &x; 右值引用 新标准在拷贝构造函数.拷贝赋值运算符和析构函数之外,还增加了移动构造函数和移动赋值运算符,而这二位就需要右值引用的支持. 1. 延长将亡值的生命. 1 /

C++11 新特性之 tuple

我们在C++中都用过pair.pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同.pair可以使用make_pair构造 pair<int, string> p = make_pair(1, "a1"); 如果传入的参数为多个,那么就需要嵌套pair,如下代码 #include <iostream> #include <map> using namespace std; int main() { //<int, string,

【C++11】30分钟了解C++11新特性

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 什么是C++11 C++11是曾经被叫做C++0x,是对目前C++语言的扩展和修正,C++11不仅包含核心语言的新机能,而且扩展了C++的标准程序库(STL),并入了大部分的C++ Technical Report 1(TR1)程序库(数学的特殊函数除外). C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto.decl

[C++11新特性]第二篇

0.可变数量参数,可变函数模版,变长模版类 c++98可变数量参数 #include<cstdio> #include<cstdarg> double SumOfFloat(int count, ...) { va_list ap; double sum=0; va_start(ap,count); for(int i=0;i<count;i++) sum+=va_arg(ap,double); va_end(ap); return sum; } int main() { p

[cocos2d-x] 一些C++ 11新特性的引入

1.auto关键字的使用 auto关键字原理     在定义变量的时候必须申明类型,c++是强语言类型,在编译阶段需要知道类型,这样的好处是程序效率更高,而动态语言不需要类型申明的需要自推导变量类型.使用了auto是不是c++效率会变慢?完全不是,因为在编译阶段编译器已经帮程序员推导好了变量的类型.前提条件是编译器可以根据当前的程序的状态推导出变量类型.只是编译器更加智能,可能会增加编译工作,但是不会影响运行效率. 实例1:申明普通变量 auto num = 10; 实例2: vector<st

C++11 新特性之 decltype关键字

decltype关键字用于查询表达式的类型.与其他特性结合起来之后会有意想不到的效果. decltype的语法是 decltype (expression) 实例: #include <iostream> #include <typeinfo> using namespace std; int main() { int i; double d; float f; struct A { int i; double d; }; decltype(i) i1; cout <<