C++11:通用为本,专用为末(二)

2014-11-24 07:13:38 · 作者: · 浏览: 3
st lvalue ref PerfectForward(move(d)); // const rvalue ref } 完美转发的一个作用就是包装函数,将上面的例子稍作修改:

#include 
           
            
using namespace std;
void RunCode(int && m) { cout << "rvalue ref" << endl; }
void RunCode(int & m) { cout << "lvalue ref" << endl; }
void RunCode(const int && m) { cout << "const rvalue ref" << endl; }
void RunCode(const int & m) { cout << "const lvalue ref" << endl; }
template 
            
              void PerfectForward(T &&t) { RunCode(forward
             
              (t)); } int main() { int a; int b; const int c = 1; const int d = 0; PerfectForward(a); // lvalue ref PerfectForward(move(b)); // rvalue ref PerfectForward(c); // const lvalue ref PerfectForward(move(d)); // const rvalue ref }
             
            
           

5 列表初始化:C++11中允许对类成员就地初始化,如下:

class test{
   public:
       int data{10};//int data=10;两种均可以,但是int data(10)不可以
};
对数组的初始化int a[5]={1,2}采用{}列表初始化,C++11中有一种初始化形式就是{}列表初始化,如:

vector
           
             c{1,2,3}; 
int* p=new int(10); 
map
            
              > a={{1,1.0},{2,2.0}}//惊艳的是列表初始化针对vector,map这样内置容器依然可以初始化
            
           

头文件 里有个initialize_list 模板类以其为构造函数为参数,自定义类型也可以使用列表初始化:

#include 
           
            
#include 
            
              using namespace std; enum Gender {boy, girl}; class People { public: People(initializer_list
             
              > l) { // initializer_list的构造函数 auto i = l.begin();//自动推断i的类型 for (;i != l.end(); ++i) data.push_back(*i); } private: vector
              
               > data;//这里可以换成其它数据成员如vector
               
                ,也可以列表初始化 }; People ship2012 = {{"Garfield", boy}, {"HelloKitty", girl}};
               
              
             
            
           
函数参数列表也可以列表初始化:

#include 
           
            
using namespace std;
void Fun(initializer_list
            
              iv){ } int main() { Fun({1, 2});//函数参数列表初始化 Fun({}); // 空列表 }
            
           
类和结构体的成员函数也可以使用列表初始化,包括一些操作符的重载函数:

#include 
           
            
#include 
            
              using namespace std; class Mydata { public: Mydata & operator [] (initializer_list
             
               l)//重载[],将需要操作的下标放入idx { for (auto i = l.begin(); i != l.end(); ++i) idx.push_back(*i); return *this; } Mydata & operator = (int v)//同一下标的值都设为v { if (idx.empty() != true) { for (auto i = idx.begin(); i != idx.end(); ++i) { d.resize((*i > d.size())   *i : d.size());//注意要不断调整d的大小,以防止数组越界 d[*i - 1] = v;//数组下标从0开始 } idx.clear(); } return *this; } void Print() { for (auto i = d.begin(); i != d.end(); ++i) cout << *i << " "; cout << endl; } private: vector
              
                idx; // 辅助数组,用于记录index vector
               
                 d; }; int main() { Mydata d; d[{2, 3, 5}] = 7;//通过重载[]使得指定的这些下标值都一样 d[{1, 4, 5, 8}] = 4; d.Print(); // 4 7 7 4 4 0 0 4 }
               
              
             
            
           
函数返回值也可以使用列表:

vector
           
             fun(){
     return {1,3};//编译器会自动推断将初始化列表构造成返回值对应的类型
}
           


6 类型收窄:一些可以使得数据变化或者精度丢失的隐式类型转换,如:int i=3.14; 。被转换后的类型无法再复原回原来的类型。C++11中使用列表初始化进行初始化的数据编译器是会检查其是否发生类型收窄的。如:int i{3.14}编译器会警告:warning: narrowing conversion of ‘3.1400000000000001e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]


7 POD类型:plain old data, plain指不存在虚函数的普通类,lod体现了与c兼容,可以用memcpy进行复制,memset进行初始化。C++11将POD分类两个概念的并集:平凡的和标准布局的。

平凡的满足以下条件:

1) 拥有平凡的默认构造函数和析构函数,即使是显示定义构造/析构函数为空{}也不再是平凡的。但是可以在构造/析构函数后加上=default使得构造/析构为默认的,此时是平凡的。

2) 拥有平凡的拷贝构造函数和移动构造函数,平凡的拷贝构造函数等同于使用memcpy进行类型的构造。可以使用=default声明默认的拷贝/移动构造函数。

3) 拥有平凡的拷贝/移动 赋值运算符。

4) 不能包含虚函数及虚基类。

可以通过模板类判断类是否平凡的: is_trivial<类名>::value若是1则是平凡的,是0不是平凡的

标准布局满足以下条件:

1) 所有非静态成员有相同的访问权限(public,protected,private)

2) 继承必须满足两种情形之一:1、派生类中有非静态成员且只有一个仅包含静态成员的基类; 2、基类有非静态成员,而派生类没有非静态成员

3) 类中第一个非静态成员的类型与其基类不同,该规则基于C++中允许优化不包含成员的基类而产生的。

class base{};
class derived:public  base{
    base b;//第一个非静态成员是基类,所以不是标准布局的
};
4) 没有虚函数和虚基类

5) 所有非静态数据成员均符合标准布局类型,其基类也符合标准布局

可以通过模板类判断类是否标准布局: is_standard_layout<类名>::value ; 若该值是1则类是标准布局的,若该值是0则类不是标准布局的。
使用POD的好处:

1) 字节赋值,安全的使用memcpy、memset等POD类型进行初始化和拷贝

2) 提供对C内存布局的兼容,使C++可以与C函数进行交互

3) 保证了静态初始化的安全有效,比如int可以直接初始化为0


8 非受限联合体:C++98中并不是所有数据类型都能够成为union的数据成员,不允许联合体拥有静态或引用类型的成员。 C++11中取消了联合体对于数据成员的限制,任何非引用类型都可以成为联合体的数据成员,成为非受限联合体。但是还是不要在联合体中使用静态成员。


9 用户自定义字面量:C++1