-
static_assert 声明
static_assert 声明在编译时测试软件断言,这与在运行时进行测试的其他断言机制不同。 如果断言失败,则编译也将失败,且系统将发出指定的错误消息。
const int nValue = 3; static_assert(nValue < 10, "Error");这样编译时就会报出Error的错误提示信息。
-
decltype作为操作符
用于返回表达式的数据类型。
int Add(int a, int b) { return a+b; } double dVal = 0.1; const double dVal0 = 0.2; const double& dVal1 = &dVal; decltype(dVal) dVal2 = 0.3; // dVal2是double类型 decltype(0.2) dVal3 = 0.2; // dVal3是double类型 decltype(dVal1) dVal4 = &dVal0; // dVal4是const double&类型 decltype(Add(3, 4)) var = 4; // var是函数返回的类型即int类型 decltype((dVal)) dVal5 = &dVal; // decltype((variable))多括号结果永远是引用 int odd[] = {1, 3, 5, 7, 9}; int even[] = {0, 2, 4, 6, 8}; typedef int ArrType[5]; ArrType *Fun1(int i) { return (i % 2) ? &odd : &even; } decltype(odd) *Fun2(int i) { return (i % 2) ? &odd : &even; } ArrType *arr1 = Fun1(1); ArrType *arr2 = Fun2(2);
Fun2使用decltype表示它的返回类型是个指针,并且该指针类型与odd类型一致。因为odd是数组,所以Fun2返回一个指定5个整数的数组的指针。因为decltype(odd)类型的结果是数组,所以如果想Fun2返回指针则必须在函数声明时加上*符号。
-
使用尾置返回类型
尾置返回类型(trailing return type)是在形参列表后面以->符号开始标明函数的返回类型,并在函数返回类型处用auto代替。尾置返回类型即可以直接指明类型,也可以用decltype推出出类型。形式:
auto Function(int i)->int auto Fun3(int i)->int(*)[5] // 返回指定数组的指针 int n = 10; auto Function(int i)->decltype(n) template<class T, class W> auto Function(T t, W w)->decltype(t+w) { return t +w; }
// 如果是自定义类型,则应该重载+实现t+w
注:C++14中,已经将尾置返回类型去掉了,可以直接用auto推导出类型。
参考:msdn.microsoft.com/en-us/library/dd537655(v=vs.100).aspx
-
auto关键字
c++11修改了auto关键字的作用,auto类型说明符能让编译器替我们去分析表达式的初始化值来推导出变量的类型。
类型推导
int j = 0; auto m = j; // m是int类型 auto n = 0; // 0默认是int类型 map<int,list<string>>::iterator i = m.begin(); auto i = m.begin(); const int* const pInt = new int(2); auto *pAuto = pInt; // pAuto为int* cosnt类型,忽略顶层const保留底层const *pAuto = 4; // Error pAuto = new int(5); // OK const auto& ref = 42; // 0K int Add(int a, int b){return a+b;} auto ret = Add(3, 4); // ret是intauto和动态分配
auto pInt1 = new int(4); int nValue = 4; auto pInt2 = new auto(nValue); //以nValue类型动态申请内存并以nValue赋值 delete pInt2; // 以下是申请指向&nValue的指针 auto** ppInt = new auto(&nValue); int** ppInt = new int*; *ppInt = &nValue; delete ppInt;注:VS2010中对auto的动态分配支持有Bug,delete时会报错,所以VS2010中不允许使用此功能。
参考:https://msdn.microsoft.com/en-us/library/dd293667(v=vs.100).aspx
-
Lambda表达式
Lambda表达式就是匿名函数。Lambda表达式表示一个可调用的代码单元。与其他函数一样,Lambda具有一个返回类型、一个参数列表和一个参数体。一个Lambda表达式具有如下形式:
[capture list](parameter list))->return type { function body}
Capture list(捕获列表)Lambda函数中定义的局部变量列表,可以为空。
Parameter list、function body和普通函数一样。
return type,尾置类型指明,一般情况可以没有,编译器会自动推导出返回类型。当函数体有多个返回值时,编译会产生错误,需要指明返回类型。
string strRet = [](const string& str) { return "Hello from " + str; }("Lambda"); auto fun = [](const string& str)->string { return "Hello from " + str; }; strRet = fun("Lambda");Lambda表达式可以作为函数参数,例如在算法函数中调用时:
int arr[10] = {0}; generate(arr, arr+10, []()->int { return rand() % 100; });捕获列表的使用,指出数组第1个大于10的元素.
int nFlag = 10; int nArr[] = {5, 3, 2, 11, 4, 22}; auto first = find_if(nArr, nArr+6, [nFlag](int nValue){return nValue > nFlag;});
-
右值引用
为了支持移动语义,C++11引入了新的引用类型——左值引用(RValue Reference)。右值引用,即绑定到右值的引用,通过&&来获取右值的引用。
左值右值
左值:有具体的名字,作用域不止当前语句。
右值:匿名、作用域仅在当前语句。
C++11里面对此作出的定义是:Things that are declared as rvalue reference can be lvalues or rvalues. The distinguishing criterion is: if it has a name, then it is an lvalue. Otherwise, it is an rvalue.
普通类型的常量都是左值,但是字符串常量因为生存周期是全局的,所以字符串常量是左值。
int&& nRRef = 1;
const string& strLRef = “LValue Reference”;
// nRRef虽然是左值引用,但它是具名的,所以nRRef是左值
右值引用
右值一旦离开当前语句,其生存期就会被销毁。而右值引用则将右值的有效性移动到右值引用这个左值上。
通过右值引用的定义可以看出它的主要作用是将临时变量的生存周期给转移了,这样就减少创建变量销毁对象的损耗。
构造函数和赋值函数是创建对象最常用函数,也是右值引用发挥作用的地方。
移动构造函数和移动赋值函数
class CMyString { public: CMyString() { m_data = NULL; m_len = 0; } CMyString(const char* p) { m_len = strlen (p); Init(p); } CMyString(const CMyString&& str) { m_len = str.m_len; m_data = str.m_data; str.m_data = NULL; std::cout << "Copy Constructor is called! source: " << m_data << std::endl; } CMyString& operator=(const CMyString&& str) { if (this != &str) { m_len = str.m_len; m_data = str.m_data; str.m_data = NULL; } std::cout << "Copy Assignment is called! source: " << m_data << std::endl; return *this; } virtual ~CMyString() { if (m_data) delete[] m_data; } private: void Init(const char *s) { m_data = new char[m_len+1]; memcpy(m_data, s, m_len); m_data[m_len] = '