代码改变世界

Visual C++ 2010新功能之auto关键字

2011-06-03 10:40  Rollen Holt  阅读(2090)  评论(6编辑  收藏  举报

C语言里面其实就已经有auto关键字了,只不过很少用到,当我们在C或者以前的C++中,auto关键字基本上可以被无视:

比如这个局部变量: int a = 100; auto int a = 100;并没有什么区别,但是在VC2010中, auto已经有了新的含义,它可以对类型进行推断使得我们在使用的时候可以这样auto a = 100;那么a就是int类型,初始值为100. 下面是一个测试程序for VC2010

#include <iostream>

#include <string>

#include <typeinfo>

#include <functional>

using namespace std;

template <typename T>

void doshow( T t )

{

cout<<typeid(t).name() << endl;

}

#define Show( test ) /

{ /

cout<< #test<<" : "; /

auto t = test; /

doshow(t); /

}

extern "C"

{

class Test2

{

}t2;

}

class Test3

{

public:

void print()

{

}

}t3;

namespace ttt

{

class Test4

{

}t4;

}

void testprint( int, double, float, float*, double* )

{

}

int main()

{

Show( 2 );

Show( 3.0f );

Show( 3.0 );

Show( "test" );

Show( std::string("test") );

Show( L"Test" ); 

Show( std::wstring(L"test") );

Show( (const int*)0 );

Show( (const int* const)0 );

class Test1

{

}t1;

Show( t1 );

Show( t2 );

Show( t3 );

Show( ttt::t4 );

Show( &Test3::print );

Show( std::mem_fun(&Test3::print) );

Show( testprint );

Show( std::bind( testprint ) );

Show( std::function< void () >() );

Show( doshow<double> );

return 0;

}

运行的结果:

2 : int

3.0f : float

3.0 : double

"test" : char const *

std::string("test") : class std::basic_string<char,struct std::char_traits<char>

,class std::allocator<char> >

L"Test" : wchar_t const *

std::wstring(L"test") : class std::basic_string<wchar_t,struct std::char_traits<

wchar_t>,class std::allocator<wchar_t> >

(const int*)0 : int const *

(const int* const)0 : int const *

t1 : ?AVTest1@?L@?main@

t2 : class Test2

t3 : class Test3

ttt::t4 : class ttt::Test4

&Test3::print : void (__thiscall Test3::*)(void)

std::mem_fun(&Test3::print) : class std::mem_fun_t<void,class Test3>

testprint : void (__cdecl*)(int,double,float,float *,double *)

std::bind( testprint ) : class std::tr1::_Bind_fty<void (__cdecl*)(int,double,fl

oat,float *,double *),struct std::tr1::_Notforced,class std::tr1::_Bind0<struct

std::tr1::_Callable_obj<void (__cdecl*)(int,double,float,float *,double *),0> >

>

std::function< void () >() : class std::tr1::function<void __cdecl(void)>

doshow<double> : void (__cdecl*)(double)

可以看出只要你提供合法的初始值,那么它就可以为你推断出类型来。

当然像这样的代码是不能通过编译的:auto a;

因为auto关键字要求必须有初始值。

error C3531: a类型包含“auto”的符号必须具有初始值设定项

下面的文字来自MSDN

C++ 标准为 auto 关键字定义了初始和修订的含义。在 Visual C++ 2010 之前,该关键字在自动存储类中声明变量,即具有局部生存期的变量。从 Visual C++ 2010 开始,该关键字从声明的初始化表达式中推导变量的类型。 使用 /Zc:auto[-] 编译器选项可指示编译器使用 auto 关键字的初始或修订的含义。

/Zc:auto[-] 编译器选项指示编译器如何使用 auto 关键字来声明变量。如果指定默认选项 /Zc:auto,编译器从其初始化表达式中推导声明的变量的类型。如果指定 /Zc:auto-,编译器将该变量分配给自动存储类。

2010.6.24Patch

        感谢yangjian8915提醒,你说的那个用法确实更能体现它的价值,不过另外还要谢谢你这个提醒让我想到一个我曾经遇到的问题,与大家分享,下面是我在做wxWidgets的时候遇到的问题:

#include <iostream>

using namespace std;

#define WXUSINGDLL

#include <wx/wx.h>

int main()

{

wxArrayString aryTest;

aryTest.push_back(wxT("te"));

for( wxArrayString::iterator it = 0; it<aryTest.begin(); ++it )

{

   if( (*it).CmpNoCase( wxT("test") ) )

   {

    // do sthing

   }

}

return 0;

}

       我的平台是VC2008,这是当时的一段出错的代码,编译器在编译时并未报错。造成错误的原因是粉色背景的那一句,之所以会有这样的代码是因为最初我想用下标来访问,后来又换成了迭代器,但是初始值却忘了改。这样的代码一运行必然会出错。

        yangjian8915同学的留言让我猛然醒悟,如果用auto在编译时就能得到错误提示或者是警告,因此我改动了一下放到VC2010下面:

#include <iostream>

using namespace std;

#define WXUSINGDLL

#include <wx/wx.h>

int main()

{

wxArrayString aryTest;

aryTest.push_back(wxT("te"));

for( /*wxArrayString::iterator*/auto it = 0; it<aryTest.begin(); ++it )

{

   if( (*it).CmpNoCase( wxT("test") ) )

   {

    // do sthing

   }

}

return 0;

}

        结果我得到一个编译错误:

main.cpp(13): error C2446: <”: 没有从“wxArrayString::iterator”到“int”的转换

           没有使该转换得以执行的上下文

main.cpp(13): error C2040: <”:“int”与“wxArrayString::iterator”的间接寻址级别不同

main.cpp(15): error C2100: 非法的间接寻址

main.cpp(15): error C2228: .CmpNoCase”的左边必须有类/结构/联合

       总结:

       1.auto可以让我们避免一些错误,为我们提供一些方便。

       2.设计的时候要注意,不要自摆乌龙,比如wxWidgets这里让0能够成功转型成iterator是有问题的,至少STLiterator无法直接从整形转换过去。

       3. 修改代码的时候要谨慎。

    Patch

       什么时候不应该用auto:

      1. 需要明确的告诉阅读者类型的时候。(代码可读性问题)

       2. 要在多个编译器下面编译的时候。(并非每个编译器都支持auto)

      3.当你要定义string而用const char*初始化的时候(以及类似的情况)。

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

也许举这个例子更能体现它的价值~~ 

std::map< std::string, std::vector<std::string> > map_str_vec; 

... 

此时,用: 

for (auto i = map_str_vec.begin(); i != map_str_vec.end(); ++i) 

{...} 

替换 

for (std::map< std::string, std::vector<std::string> >::iterator i = map_str_vec.begin(); i != map_str_vec.end(); ++i) 

{...} 

更能体现新的auto含义的好处