原文地址:http://www.codeproject.com/Articles/312029/Cplusplus-A-Glance-part-of-n
C++的里程碑
1983-第一个商业化的C++编译器
1998-C++标准化委员会标准化了C++[C++98]
2003-发布了一个补丁包,无新特性[C++03]
2005-一个技术报告“库技术报告”(简称TR1)公布。
2011-引进了许多重要的特性,并且增强了C++标准库
从上面可以看出,这次迭代是有史以来最更改最大的(是的,STL或许增加很多)。
我们需要了解这个新标准吗??
当然要。越快越好。抵抗变化时我们人类的天性。当我们掌握的语言或项目不再变化处于静态时,我们开发者离失业也就不远了。我们喜欢动态变化的项目,对于编程语言也一样。变化时不可避免的,专家委员会经过近十年的头脑风暴的成果显然十分有意义。
及时我们对这次在代码迭代中的更新不感兴趣,快速浏览一下这些特性也会帮助我们避免在编码之前使用旧的编译器。再说,只是简单把编译器换成支持C++11特性的,我们即可享受到C++11带来的好处,因为他的标准库增强了,性能更好了。所以如果你的项目用STL容器或算法,尽快更换编译器。
特性 | 目的 | vs2010支持? |
auto | 可用性增强 | 支持 |
decltype | 可用性增强 | 支持 |
Trailing return types | 可用性和性能增强 | 支持 |
Right angle brackets | 可用性增强 | 支持 |
static_assert | 可用性增强 | 支持 |
nullptr | 可用性和性能增强 | 支持 |
Strongly typed enums | 类型安全增强 | 部分支持 |
Rvalue references | 性能增强 | 支持 |
Move semantics | 性能增强 | 支持 |
long long | 性能增强 | 支持 |
Override control | 可用性增强 | 支持 |
Lambda expressions | 可用性和性能增强 | 支持 |
preventing narrowing | 性能增强 | 不支持 |
Range based for-loops | 可用性和性能增强 | 不支持 |
array | 支持 |
Really smart pointers [unique_ptr, shared_ptr, weak_ptr] | 支持 |
bind and function | 支持 |
tuple | 支持 |
unoredered_map,unordered_set | 支持 |
forward_list | 支持 |
…… |
auto i=5;//i将会定义为int类型 int n=3; double pi=3.14; auto j=pi*n;//j将会是double类型
//假设有一个Map,存储 int和map(int,int) map<int, map<int,int> > _Map; //定义这个map的迭代器 map<int, map<int,int>>::const_iterator itr1=_Map.begin(); //如果使用auto将会变得简单 const auto itr2=_Map.begin();现在来看一个变量类型不易知的例子
template<class U, class V> void Somefunction(U u, V v) { ??? result = u*v; // result的类型是什么呢 ??? // 使用auto的话,让编译器来决定result的类型 auto result = u*v; }
关于这个特性的给几个例子:
1、我们可以使用const、volatile、引用&、右值rvalue引用&&(&&-将会很快了解)修饰auto关键
auto k = 5; auto* pK = new auto(k); auto** ppK = new auto(&k); const auto n = 6;2、auto修饰的变量必须要初始化
auto m; // m 应该初始化3、auto不能与类型修饰符一起用
auto int p; // 不能这样用4、函数和模板的参数不能用auto修饰
void MyFunction(auto parameter){} // 不能用auto修饰函数参数 template<auto T> // 没意义-不允许 void Fun(T t){}5、在堆上定义的变量,如果用auto修饰,必须初始化
int* p = new auto(0); //正确 int* pp = new auto(); // 应该初始化 auto x = new auto(); // Hmmm ... 没初始化 auto* y = new auto(9); // 正确,这里y是int* auto z = new auto(9); //正确,这里z是int* (不是int)6、auto是一个类型占位符,但是auto不能定义自己的类型。因此auto不能用来做类中转换或者与sizeof和typeid相关的操作
int value = 123; auto x2 = (auto)value; // 不能用auto转换 auto x3 = static_cast<auto>(value); // 同上7、用一个auto修饰的多个变量必须初始化为同样的类型
auto x1 = 5, x2 = 5.0, x3='r'; // 这里太多类型,不能这样用8、除非修饰引用,auto把变量类型转换为CV修饰符(const和Volatile修饰符)
const int i = 99; auto j = i; // j 是int类型,而不是const int j = 100 // 正确,j不是const // 试一下引用 auto& k = i; // k是const int& k = 100; // 错误,ks是const // 对volatile修饰符,同理9、除非定义引用,否则auto将把数组退化为指针
int a[9]; auto j = a; cout<<typeid(j).name()<<endl; // 将会输出 int* auto& k = a; cout<<typeid(k).name()<<endl; // T将会输出 int [9
template<class U, class V> void Somefunction(U u, V v) { result = u*v; // result是什么类型呢 decltype(u*v) result = u*v; // 哈哈 ....我们得到了我们想要的 }在下一节,我将会介绍联合使用auto和decltype来声明模板函数,模板函数的返回值局定于模板的参数
int add(int i, int j) { return i+j; } decltype( add(5,6) ) var = 5; // var的类型是add函数的返回值类型-int
struct M { double x; }; double pi = 3.14; const M* m = new M(); decltype( (m->x) ) piRef = pi; // 注意,由于内部括号,内部的声明被当做表达式 // 而不是当做成员变量x, x类型是double,且是左值 // declspec是double&,‘m’是const指针 // 所以返回是const double& // 所以变量piRef的类型是const double&
int foo(){} decltype( foo() ) x; // x是int类型,在运行时不调用foo(
template<class U, class V> ??? Multiply(U u, V v) // 怎么确定返回值类型 { return u*v; }
template<class U, class V> decltype(u*v) Multiply(U u, V v) // 因为在Multiply之前,u和v没有定义,怎么办!! { return u*v; }
template<class U, class V> auto Multiply(U u, V v) -> decltype(u*v) // 注意->在定义函数括号之后. { return u*v; }
与其他特性相比,这个不一个大的特性。但是C++开发者追求完美,这就是一个例子。
static_assert:
这个宏可以用来检验编译时的错误。编译阶段是相对运行阶段而言的。这个特性可以用来在编译阶段检查程序的常量的值。
这个宏的用法是用一个bool值和string值来测试表达式。如果表达式值为false,那么编译器给出错误,这个错误包含一个string值;如果
表达式为true,那么这个宏没有任何影响。
我们可以在以下地方使用static_assert
A、命名空间/全局作用域
static_assert(sizeof(void *) == 4, "Oops...64-bit code generation is not supported.");
B、类作用域
template<class T, int _n> class MyVec { static_assert( _n > 0 , "How the hell the size of a vector be negative"); }; void main() { MyVec<int, -2> Vec_; // 上面这一行将会抛出如下错误( 在vs2010编译器): // > \main_2.cpp(120) : error C2338: How the hell the size of a vector be negative // > main_2.cpp(126) : see reference to class template instantiation 'MyVec<t,_n />' // being compiled // > with // > [ // > T=int, // > _n=-2 // > ] // 这个就会不 MyVec<int, 100> Vec_; }C、块作用域
template<typename T, int div> void Divide( ) { static_assert(div!=0, "Bad arguments.....leading to division by zero"); } void main() { Divide<int,0> (); // 上面这一行将会产生如下错误 // error C2338: Bad arguments.....leading to division by zero }务必记住,static_assert是用来检验编译时错误的,不能用来检查在运行阶段才能确定的值,例如函数的参数。
void Divide(int a, int b) { static_assert(b==0, “Bad arguments.....leading to division by zero”); // 对不起,伙计!上面的不能用static_assert,用其他方法吧 }static_assert在调试模板时非常有用。如果模板的常量表达式不依赖模板参数,编译器立即计算常量表达式的值。否则在模板被实例化时,编译器计算常量表达式的值。
nullptr:
这个特性被引进主要是考虑到了使用NULL宏时,容易出错。在编译阶段,NULL预处理时替换为0,这容易导致歧义。例如
void SomeFunction(int i){ } void SomeFunction(char* ch) { }