VC10中的C++0x特性:Lambdas,auto,以及 static_assert
简介
这一系列文章介绍Microsoft Visual Studio 2010 中支持的C++ 0x特性,目前有三部分。
Part 1:介绍了Lambdas, 赋予新意义的auto,以及 static_assert;
Part 2:介绍了右值引用(Rvalue References);
Part 3:介绍了表达式类型(decltype)。
Microsoft Visual Studio 2010 九月社区技术预览版 (CTP)所带的Visual C++编译器对四个C++0x语言特性提供了支持,也就是 lambdas,auto,static_assert,以及 rvalue references (右值引用,译注:后面不再对这个词进行翻译)。今天,我将详细介绍前三个特性。(很快我将贡献一整篇幅的文章来解释右值引用,仅仅是因为再在这里解释的话将会加大这篇已经很长的文章的篇幅)
首先,说明一些事情:
1,今天的这篇文章是由 Stephan T. Lavavej,Visual C++库的开发人员以及C, A, 与 T读者投书栏带给你们的。注意作为库的开发人员,我并没有实现这些特性。那是 Jonathan Caves,前端编译器开发者,选举标准委员会成员以及所有“忍者”(鲜为人知的高手)的成果。
2,我将 Visual C++ compiler in VS 2010 简称为 VC10 ( VS 2008 包含 VC9,VS 2005 包含 VC8,等等。 - 10 并不比 2010 简短)
3,C++0x 指的是即将到来的 C++ 标准,现在还在起草中。(C++标准委员会希望它可以在 2009 年完成,称作 C++ 09;玩笑话说如果它推迟到 2010 或者更晚的话,“x” 将是十六进制的了)。 C++ 98 和C++ 03 指的是当前的 C++ 标准。(在这里不回顾历史了, C++ 标准 2003 仅仅是最初的 C++ 1998 标准 的“补丁”版,对大部分人来说可以忽略两者间的区别。C++ 03 和 C++ 0x 模样虽然看起来差不多,但完全不同)
4,我要感谢标准委员会开发出这些奇妙而有用并富有艺术的特性。他们也在以下站点上提供了重要的文档:
C++0x 语言特性:
http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2705.html
C++0x 库特性:http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2706.html
C++0x 进行中的草案:
http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2798.pdf
5,总是会有bug的(虽然希望不会太多),这也就是发布 CTP 版本的主要目的(让用户测试发现 bug )。请通过 Microfsoft 把这些 bug 报告给我们。
现在,让我们来审视这些特性吧!
lambdas
在 C++ 0x 中,“lambda 表达式”隐式定义并构建不具名函数对象,这些对象就像手写函数对象一样。下面是 lambda “Hello,World”入门级的示例:
C:\Temp>type meow.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); cout << endl; } C:\Temp>cl /EHsc /nologo /W4 meow.cpp > NUL && meow 0 1 2 3 4 5 6 7 8 9 |
[] 操作符是 lambda 导引符, 它告诉编译器一个 lambda 表达式开始了。 (int n) 是 lambda 参数声明,它告诉编译器不具名函数对象类的函数调用操作符带有哪些参数, { cout << n << " "; } 是复合声明,它是不具名函数对象类的函数调用操作符的函数体。不具名函数对象类的函数调用操作符默认返回 void.
这样,C++0x 在内部将它转换成如你在C++ 98 下编写的一样代码:
C:\Temp>type meow98.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
struct LambdaFunctor { void operator()(int n) const { cout << n << " "; } };
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
for_each(v.begin(), v.end(), LambdaFunctor()); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 meow98.cpp > NUL && meow98 0 1 2 3 4 5 6 7 8 9 |
现在我将不再累述类似“不具名函数对象类的函数调用操作符默认返回 void”这样的话,开始换用“lambda 函数返回 void”的说法,但是记住 lambda 表达式做了些什么是很重要的,那就是:定义类并构建对象。
当然,lambda 的复合声明部分(函数体部分)可以包含多个声明语句,譬如:
C:\Temp>type multimeow.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { 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; }
C:\Temp>cl /EHsc /nologo /W4 multimeow.cpp > NUL && multimeow 0 even 1 odd 2 even 3 odd 4 even 5 odd 6 even 7 odd 8 even 9 odd |
C:\Temp>type cubicmeow.cpp #include <algorithm> #include <deque> #include <iostream> #include <iterator> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
deque<int> d;
transform(v.begin(), v.end(), front_inserter(d), [](int n) { return n * n * n; });
for_each(d.begin(), d.end(), [](int n) { cout << n << " "; }); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 cubicmeow.cpp > NUL && cubicmeow 729 512 343 216 125 64 27 8 1 0 |
在这里, n * n * n 的类型是 int,所以 lambda 函数返回 int.
有着复杂复合声明语句的 lambda 函数不会自动推断返回类型,你必须显式指定返回类型。