本节书摘来自异步社区出版社《Visual C++ 2012 开发权威指南》一书中的第2章,第2.1节,作者: 尹成 , 朱景尧 , 孙明龙 , 胡耀文,更多章节内容可以访问云栖社区“异步社区”公众号查看。
第2章 Visual C++2012语言新特性
Visual C++ 2012 开发权威指南
有一种新的C++标准就有一种新版本的Visual C++,新的版本Visual C++将更加符合C++标准!在其发展过程中新的C++标准被(乐观)称为C++0x。它最后被发布在2011年,现在称为C++11。
对于Visual C++,它有三个不同版本的数字,有不同的内部版本和编译器版本(cl.exe和_MSC_VER宏-显示不同,因为我们C++编译器早在Visual C++中的"可视化")。例如:
VS 2005 == VC8 == _MSC_VER 1400
VS 2008 == VC9 == _MSC_VER 1500
VS 2010 == VC10 == _MSC_VER 1600
在内部就只是VC11。如果读了C++0x标准,以及熟悉VC的诸个版本的不同,就会理解。
2.1 Visual C++2012的语言新特性(1)
Lambda被选入工作文件(v0.9)和可变lambda添加(v1.0)后,标准化委员会彻底改革措辞,推出lambda 1.1版。这才能实现页本页,但我们已经实现了它VC11。Lambda v1.1措辞澄清在像引用静态成员或嵌套的lambda的情况下该怎么办。这可以修复Bug引发复杂的lambda的一群。此外,lambda现已转换为VC11中的函数指针。这不是在N2927的措辞,但不管怎样,它作为lambda v1.1的一部分。这是跨国公司直接投资5.1.2 [expr.prim.lambda]/6:“没有lambda捕获lambda表达式的封闭类型,有公共非虚拟、非明确const转换函数具有相同的参数和返回类型,如封闭类型的函数调用操作符的函数指针。此转换函数返回的值应函数的地址调用时,已调用该封闭类型的函数调用操作符相同的效果。”
lambda表达式隐式定义并构造未命名函数对象。lambda提供了一种轻型自然语法来定义使用lambda的函数对象,而不产生性能开销。
函数对象是自定义标准模板库(STL)算法行为的非常强大的方式,可以封装代码和数据(与普通函数不同)。但定义函数对象不太方便,因为需要编写完整的类。此外,它们不是在要用到它们的源代码中定义的,这种非局部性增加了这些对象的使用难度。库已尝试缓解一些复杂性和非局部性问题,但帮助不大,因为语法有点复杂而且编译器错误不是很友好。使用库中的函数对象也会降低效率,因为定义为数据成员的函数对象不是内联对象。
lambda表达式解决了这些问题。下面的代码段显示了一个lambda表达式,该表达式在程序中用于从整数向量中删除变量x和y之间的整数。
v.erase(remove_if(v.begin(),
v.end(), [x, y](int n) {
return x < n && n < y; }),
v.end());```
第二行显示了该lambda表达式。方括号(称为lambda引导)指示lambda表达式的定义。此lambda采用整数n为参数,lambda生成的函数对象具有数据成员x和y。若与一个等效的手写函数对象进行比较,可看到lambda的方便性和省时性:
class LambdaFunctor {
public:
LambdaFunctor(int a, int b) : m_a(a), m_b(b) { }
bool operator()(int n) const {
return m_a < n && n < m_b; }
private:
int m_a;
int m_b;
};
v.erase(remove_if(v.begin(), v.end(),
LambdaFunctor(x, y)), v.end());`
C++的新标准C++0x虽然还没有正式发布,但是已经进入了feature freeze的阶段,很多人都在猜测C++0x中的x到底是9还是10,从目前的情况来看,9是最大的可能了。Visual Studio 2012作为下一代开发工具,当然不会错过对新的C++标准C++0x的支持。除了随着之前发布的Visual C++Feature Pack而引入的TR1包含的部分特性外,在新的Visual Studio 2012中,还引入了4个重要的C++新特性。号称C++0x的“四大天王”。这些新特性的引入,必将给C++注入新的活力。
很多编程语言都支持匿名函数(anonymous function)。所谓匿名函数,就是这个函数只有函数体,而没有函数名。Lambda表达式就是实现匿名函数的一种编程技巧,它为编写匿名函数提供了简明的函数式的句法。
Lambda表达式使得函数可以在使用的地方定义,并且可以在Lambda函数中使用Lambda函数之外的数据。这就为针对集合操作带来了很大的便利。在作用上,Lambda表达式类似于函数指针和函数对象,Lambda表达式很好地兼顾了函数指针和函数对象的优点,却没有它们的缺点。相对于函数指针或是函数对象复杂的语法形式,Lambda表达式使用非常简单的语法就可以实现同样的功能,降低了Lambda表达式的学习难度,避免了使用复杂的函数对象或是函数指针所带来的错误。我们可以看一个实际的例子:
// LambdaDemo.cpp : 为控制台程序定义入口
//
#include"stdafx.h"
#include<algorithm>
#include<iostream>
#include<ostream>
#include<vector>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
vector<int> v;
for (int i= 0; i< 10;++i) {
v.push_back(i);
}
for_each(v.begin(), v.end(), [](int n) {
cout<< n;
if (n %2 == 0) {
cout<< " even";
}else {
cout<< " odd";
}
});
cout<< endl;
return 0;
}```
这段代码循环遍历输出vector中的每一个数,并判断这个数是奇数还是偶数。我们可以随时修改Lambda表达式而改变这个匿名函数的实现,修改对集合的操作。在这段代码中,C++使用一对中括号“[]”来表示Lambda表达式的开始,其后的“(int n)”表示Lambda表达式的参数。这些参数将在Lambda表达式中使用到。为了体会Lambda表达式的简洁,我们来看看同样的功能,如何使用函数对象实现:
include"stdafx.h"
include
include
include
include
using namespace std;
struct LambdaFunctor {
void operator()(int n)const {
cout<< n<< " ";
if (n %2 == 0) {
cout<< " even";
}else {
cout<< " odd";
}
}
};
int _tmain(int argc, _TCHAR* argv[])
{
vector v;
for (int i= 0; i< 10;++i) {
v.push_back(i);
}
for_each(v.begin(), v.end(), LambdaFunctor());
cout<< endl;
return 0;
}`
通过比较我们就可以发现,Lambda表达式的语法更加简洁,使用起来更加简单高效。