C++11带来的优雅语法
自动类型推导 auto
auto的自动类型推导,用于从初始化表达式中推断出变量的数据类型。通过auto的自动类型推导,可以简化我们的编程工作;
auto是在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响; 另外,似乎auto也并不会影响编译速度,因为编译时本来也要右侧推导然后判断与左侧是否匹配。auto a; // 错误,auto是通过初始化表达式进⾏类型推导,如果没有初始化表达式,就无法确定a的类型auto i = 1;auto d = 1.0;auto str = "Hello World";auto ch = 'A';
auto对引用的推导默认为值类型,可以指定引用修饰符设置为引用:
int x = 5;int & y = x; auot z = y ;// z 为intauto & z = y; // z的类型为 int&
对指针的推导默认为指针类型,当然,也可以指定*修饰符(效果一样):
int *px = &x;auto py = px;auto*py = px;
推导常量
const int *px = &x;auto py = px; //py的类型为 const int *const auto py = px ; //py的类型为const int *
萃取类型 decltype
decltype实际上有点像auto的反函数,使用auto可以用来声明一个指定类型的变量,而decltype可以通过一个变量(或表达式)得到类型;
#includeint main() { int x = 5; decltype(x) y = x; //等于 auto y = x; const std::vector v(1); auto a = v[0]; // a has type int decltype(v[1]) b = 1; // b has type const int&, the return type of // std::vector ::operator[](size_type) const auto c = 0; // c has type int auto d = c; // d has type int decltype(c) e; // e has type int, the type of the entity named by c decltype((c)) f = c; // f has type int&, because (c) is an lvalue decltype(0) g; // g has type int, because 0 is an rvalue}
有没有联想到STL中的萃取器?写模版时有了这个是不是会方便很多;
返回类型后置语法 Trailing return type
C++11支持返回值后置
例如:int adding_func(int lhs, int rhs);
可以写为:
auto adding_func(int lhs, int rhs) -> int
auto用于占位符,真正的返回值在后面定义;
这样的语法用于在编译时返回类型还不确定的场合; 比如有模版的场合中,两个类型相加的最终类型只有运行时才能确定:templateauto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}cout << adding_func (dv,iv) << endl;
auto用于占位符,真正的返回值类型在程序运行中,函数返回时才确定;
不用auto占位符,直接使用decltype推导类型:
decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs &rhs)
这样写,编译器无法通过,因为模版参数lhs和rhs在编译期间还未声明;
当然,这样写可以编译通过:decltype( (*(Lhs*)0) + (*(Rhs*)0) ) adding_func(const Lhs &lhs, const Rhs &rhs)
但这种形式实在是不直观,不如auto占位符方式直观易懂;
空指针标识 nullptr
空指针标识(nullptr)(其本质是一个内置的常量)是一个表示空指针的标识,它不是一个整数。这里应该与我们常用的NULL宏相区别,虽然它们都是用来表示空置针,但NULL只是一个定义为常整数0的宏,而nullptr是C++11的一个关键字,一个内建的标识符。
nullptr和任何指针类型以及类成员指针类型的空值之间可以发生隐式类型转换,同样也可以隐式转换为bool型(取值为false)。但是不存在到整形的隐式类型转换。 有了nullptr,可以解决原来C++中NULL的二义性问题;voidF(int a){ cout<<
区间迭代 range-based for loop
C++11扩展了for的语法,终于支持区间迭代,可以便捷的迭代一个容器的内的元素;
int my_array[5] = {1, 2, 3, 4, 5};// double the value of each element in my_array:for (int &x : my_array) { x *= 2;}
当然,这时候使用auto会更简单;
for (auto &x : my_array) { x *= 2;}
如果有更为复杂的场景,使用auto的优势立刻体现出来:
mapmap;map.insert <>("ss",1);for(auto &x : my_map){ cout << x.first << "/" << x.second;}
去除右尖括号的蹩脚语法 right angle brackets
在C++98标准中,如果写一个含有其他模板类型的模板:
vector> vector_of_int_vectors;
你必须在结束的两个’>‘之间添加空格。这不仅烦人,而且当你写成>>而没有空格时,你将得到困惑和误导的编译错误信息。产生这种行为的原因是C++词法分析的最大匹配原则(maximal munch rule)。一个好消息是从今往后,你再也不用担心了:
vector> vector_of_int_vectors;
在C++98中,这是一个语法错误,因为两个右角括号(‘>’)之间没有空格(译注:因此,编译器会将它分析为”>>”操作符)。C++0x可以正确地分辨出这是两个右角括号(‘>’),是两个模板参数列表的结尾。
为什么之前这会是一个问题呢?一般地,一个编译器前端会按照“分析/阶段”模型进行组织。简要描述如下:
词法分析(从字符中构造token)
语法分析(检查语法) 类型检查(确定名称和表达式的类型) 这些阶段在理论上,甚至在某些实际应用中,都是严格独立的。所以,词法分析器会认为”>>”是一个完整的token(通常意味着右移操作符或是输入),而无法理解它的实际意义(译注:即在具体的上下文环境下,某一个符号的具体意义)。特别地,它无法理解模板或内置模板参数列表。然而,为了使上述示例“正确”,这三个阶段必须进行某种形式的交互、配合。解决这个问题的最关键的点在于,每一个C++ 编译器已完整理解整个问题(译注:对整个问题进行了全部的词法分析、符号分析及类型检测,然后分析各个阶段的正确性),从而给出令人满意的错误消息。lambda表达式的引入
对于为标准库算法写函数/函数对象(function object)这个事儿大家已经抱怨很久了(例如Cmp)。特别是在C++98标准中,这会令人更加痛苦,因为无法定义一个局部的函数对象。
首先,我们需要在我们实现的逻辑作用域(一般是函数或类)外部定义比较用的函数或函数对象,然后,才能使用:
bool myfunction (int i,int j) { return (i