如何使用C++11 auto语法

0x00 定义

auto 是C++11中增加的一个非常有用的关键字,其核心在于类型推导(type deduction),也就是让编译器根据等号右边的表达式来决定auto实际代表的类型。注意它区别于其他语言的“动态”类型(如objective c的id和C#的dynamic),C++的auto只涉及到编译期的行为而不是运行期。

0x01 静态类型与动态类型

静态类型是指在运行之前就检查数据类型的语言,比如C/C++在编译的时候,就检查了数据类型。

动态类型是指,在运行的时候(runtime)才检查数据类型,比如php、javascript。

0x02 动态类型的优势

  1. 由程序自动从右侧表达式推导出左侧变量的类型,更加智能,减少人的工作。
  2. 运行时报错,所见即所得。

随着对编程语言易用性的需求不断扩大,对类型推到,lambda 表达式的使用越来越多。这种新特性使程序更加简洁,人写的代码减少,编译器或者执行器来辅助做更多的工作。

支持类型推导一个比较直接的好处就是可以支持lambda表达式的写法。

lambda表达式也是C++ 11开始支持的新特性,作为匿名函数,可以很少的代码定义一个功能简单的小函数。那么问题来了,我一句话定义一个函数,函数的返回值类型是啥是不是得考虑下?

lambda函数定义如下:

auto Lambda = [](QString str){return str;};

lambda函数将普通函数的函数名替换成中括号[],返回值自动推导。这样书写起来就更简洁了。

当然,这里还有个问题,c++是静态类型,如果实现这么好用的功能。那就是在编译期做检查,完成自动推导的计算。

0x03 auto的好处

1. 更优雅地使用迭代器

这里使用@Deb Haldar给的例子,使用STL map表存储学生的各科成绩。

std::map<std::wstring, std::map<std::wstring, int>> StudentGrades;

StudentGrades[L"Deb"][L"Physics"] = 96;
StudentGrades[L"Deb"][L"Chemistry"] = 92;
StudentGrades[L"Deb"][L"Math"] = 82;
StudentGrades[L"Vik"][L"Physics"] = 92;
StudentGrades[L"Vik"][L"Chemistry"] = 88;
StudentGrades[L"Vik"][L"Math"] = 91;

现在我们想打印所有的成绩,写代码是介样儿的

for (std::map<std::wstring, std::map<std::wstring, int>>::iterator outerMap_Iter = StudentGrades.begin(); outerMap_Iter != StudentGrades.end(); ++outerMap_Iter)
{
	//打印StudentGrades的第一个元素,即学生姓名
	std::wcout << outerMap_Iter->first << std::endl;
	//在写一层循环,遍历内层map
	for (std::map<std::wstring, int>::iterator innerMap_Iter = outerMap_Iter->second.begin(); innerMap_Iter != outerMap_Iter->second.end(); ++innerMap_Iter)
	{
		//打印内层map的第一个元素,即学科,第二个元素为成绩
		std::wcout << innerMap_Iter->first << " : " << innerMap_Iter->second << std::endl;
	}
	std::wcout << std::endl;
}

如果你屏幕不够宽,或者用的是笔记本看这个双层循环代码,相信水平滚轮是你心里最想咒骂的。老外也一样。此时,auto闪亮登场:

for (auto outerMap_Iter = StudentGrades.begin(); outerMap_Iter != StudentGrades.end(); ++outerMap_Iter) 
{
  //Print out the student name
  std::wcout << outerMap_Iter->first << std::endl;

  for (auto innerMap_Iter = outerMap_Iter->second.begin(); innerMap_Iter != outerMap_Iter->second.end(); ++innerMap_Iter)
  {
	 //Print the grades here
	 std::wcout << innerMap_Iter->first << " : " << innerMap_Iter->second << std::endl;
  }
  std::wcout << std::endl;
}

水平宽度节约了一半有没有?auto 再配合range-based loop 看看:

for (auto const &outer_iter : StudentGrades) 
{
  std::wcout << outer_iter.first << std::endl;

  for (auto const &inner_iter : outer_iter.second)
  {
	 std::wcout << inner_iter.first << " : " << inner_iter.second << std::endl;
  }
}

太神奇了,有没有。我们简单看下auto做了什么?

正常迭代器的声明

std::map<std::wstring, std::map<std::wstring, int>>::iterator outerMap_Iter = outerMap_Iter->second.begin();

因为auto可以自动从outerMap_Iter的类型中推导出迭代器应该是什么类型,我们就不需要自己费劲写了。

auto outerMap_Iter = outerMap_Iter->second.begin();

2. 优雅地使用lambda

没有auto类型时,我们需要使用函数对象存储lambda函数

std::function<int(int, int)> func_multiply2 = [](int a, int b) -> int { return a * b; };
std::cout << func_multiply2(2, 3) << std::endl;

用了auto之后

auto func_multiply = [](int a, int b){ return a * b; };

同时使用auto声明的对象会快于std::function声明的,详细讨论可以参见 “Effective Modern C++”。

0x04 注意

使用auto声明的对象必须初始化,必须初始化

auto s("hello"); //ok
auto x1 = 5, x2 = 5.0, x3='r'; //bad, 需要初始化成同一类型

const int i = 99;
auto j = i;       // ok, j是int型,而非const int类型


int* p = new auto(0); //ok
int* pp = new auto(); // bad

0x05 参考文献

https://www.acodersjourney.com/c-11-auto/
https://blog.csdn.net/hushujian/article/details/43196589

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值