| 1. 演进、环境与资源 
  版本:c++98(1.0),c++04,c++11(2.0),c++14
2. Variadic Template(可变参数模板)(重点,也是难点) 
  ...就是pack(包),表示任意个数、任意类型的参数
 template parameters pack:模板参数包
 function parameter types pack:函数参数类型包
 function parameter pack:函数参数包
 模板有特化的概念。重载中,函数谁会更特别,则调用更特化的。
 代码: 
     #include<iostream>
using namespace std;
namespace variadic{
	void print(){
	}
	
	template <typename T, typename... Types>
	void print(const T& firstArg, const Types&... args){
		cout << sizeof...(args) << " " << firstArg << endl;
		print(args...);
	}
	template<typename... Values> class tuple;
	template<> class tuple<> {};
	template<typename Head, typename... Tail>
	class tuple<Head, Tail...>: private tuple<Tail...>{
		typedef tuple<Tail...> inherited;
		public:
			tuple() {}
			tuple(Head v, Tail... vtail): m_head(v), inherited(vtail...) {}
			
			Head head() {return m_head;}
			inherited& tail() { return *this; }
		protected:
			Head m_head;
	};
	
	
}
using namespace variadic;  // 如果不加这一行,编译不通过 
int main(){
	int a = 1;
	char c = 'T';
	int b[10] = {0};
	string s("abs");
//	cout << b << endl;  //打印的是地址 
//	s = "dsd";  // 可以通过编译
	print(a, c, b, s); 
//	tuple<int, float, string> t(41, 6.3, "nico");
//	cout << t.head() << endl;
//	cout << t.tail().head() << endl;
	return 0;
}
3. Spaces in Template Expression、nullptr、auto 
  Spaces in Template Expression 
    vector<vector<int> > v; 可以写成 vector<vector<int> > v;(中间的空格可以不写
 nullptr 
    C++11开始,定义了空指针的常值为nullptr
 auto 
    auto可以自动推导变量的类型,当类型比较长、或者复杂的表达式 lambda,可以使用auto代替。
4. Unifrom Initialzation一致性初始化 
  
  需要注意的是,initializer_list对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值。并且,拷贝或赋值一个initializer_list对象不会拷贝列表中的元素,其实只是引用而已,原始列表和副本共享元素,本质是由于这是一种浅拷贝,二者底层上只是把一个指针同时指向一个地址。
 现在有了initializer_list<>,所有容器都接受指定类型任意数量的值用于构建或赋值等(类型要一致,{}不会进行类型转换)。
 代码: 
    vector<int> v {1, 2, 3, 4};
5. Initialzer_list 
  std::initializer_list有三个成员接口:size(), begin(), end();
6. Explicit for ctors taking more than one argument带多个参数的系数的显式 
  加入了explicit, 必须显式调用构造函数。不允许进行隐式的调用构造函数。
 代码: 
     #include<iostream>
struct Complex{
	double _real;
	double _i;
//	explicit  // 加入了explicit, 必须显式调用构造函数 
	Complex(double real, double i = 0) : _real(real), _i(i) {}
	Complex operator + (const Complex &c){
		return Complex(c._real + _real, c._i + _i);
	}
	~Complex() = default;
};
int main() {
	Complex c1(4, 2);
	Complex c2 = c1 + 5; // 编译器会隐式地调用构造函数来构造一个Complex(5)
	return 0;
}
7. Range - based for statement 
  代码: 
    vector<int> v {1,2, 3,4};
8. =default. =delete(https://blog.csdn.net/baidu_17611285/article/details/80505902) 
  big-five:默认的构造函数,默认的拷贝构造函数,默认的赋值构造函数,移动构造函数,移动赋值构造函数
 default就是专门作用于以上的big-five,表示当我们已经定义了专门的构造、拷贝构造、赋值构造、移动构造等等函数,此时编译器就不会自动加上big-five,但假如此时还希望用这些默认的函数,可加上=default来实现,如下图。而“=delete”表示的是我们不想要这个函数,若去调用加了“=delete”的函数,则编译报错。另外,“=delete“可加在任意函数,不局限于类的成员函数。default还能用于析构函数身上,但很少用到。
 =default(也可以使用在析构函数上) 
    在标准库中,default都是用于big-five的函数。
 一个类只要带着指针成员,几乎就断定需要我们自己去写出那些Big-Three(构造,拷贝构造,赋值构造,C++11就是Big-FIve);反之,如果不带指针成员,几乎就不需要自己去实现Big-Three,一般编译器默认的就够了。因为,编译器的默认拷贝是浅拷贝,带指针的就只拷贝指针本身,一般我们需要深拷贝,也就是指针所指的那块内存要重新分配,再拷贝指针。
 ? #include<iostream>
using namespace std;
class Zoo{
	private:
		int d1, d2;
	public:
		Zoo(int i1, int i2):d1(i1), d2(i2) {}
		// 由于写了构造函数,系统不会自动在生成构造函数。
		// 故如果不写下面这一行,Zoo z1;将会报错。 
		Zoo() = default;   
		Zoo(const Zoo&) = delete;
		Zoo(Zoo &&) = default;
		Zoo& operator = (const Zoo&) = default;
		Zoo& operator = (const Zoo&&) = delete;
		virtual ~Zoo() {}
}; 
int main() {
	Zoo z1;
//	Zoo z2(z1);   //  由于使用了Zoo(const Zoo&) = delete;,故这一行报错 
	return 0;
}
9. Alias Template(模板别名)(8.Alias Template(模板别名)_baidu_17611285的博客-CSDN博客_alias template) 
  using这种方法类似于C++中的typedef,但这种C++11的新机制不仅仅是为了通过设置模板别名来少写几个字,且其也无法通过typedef或#define代替
  #include<iostream>
#include<vector>
using namespace std;
//  template要放在函数外面 
// 使用typedef语法复制等 
template<typename T>
using Vec = vector<T, allocator<T>>;
template <typename T, template <class> class Container>
class XCLs {
	private:
		Container<T> c;
	public:
		XCLs() {
			for(long i = 0; i < 10; i++)
				c.insert(c.end(), T()); 
				
//			output_static_data(T());
			Container<T> c1(c);
			// std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝所以可以提高利用效率,改善性能.。
			Container<T> c2(std::move(c));
			c1.swap(c2);
		}
};
int main() {
	XCLs<int, Vec> c1;
	return 0;
}
10.Template template parameter 
  11. Type Alias, noexception, override, final(C++新特性之Type Alias、noexcept、override、final_u013635579的博客-CSDN博客) 
  
  
  override 
    在C++11中提供的override关键字可以解决这一问题,它标记派生类中的虚函数,如果基类中的虚函数没有被覆盖,编译器则报错
 final 
    final新增两种功能:(1)、禁止基类被继承,(2)、禁止虚函数被重写;
12. decltype 
  decltype(表达式),返回表达式(可以使函数)的类型。
 dectype并不会执行表达式,只是推出类型,而auto会执行。
13. lambdas(C++之Lambda表达式 - 季末的天堂 - 博客园) 
  
  [函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
 C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。
 =。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是值传递方式(相
 &。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式
 (相当于是编译器自动为我们按引用传递了所有局部变量)。
 this。函数体内可以使用 Lambda 所在类中的成员变量。
 a。将 a 按值进行传递。按值进行传递时,函数体内不能修改传递进来的 a 的拷贝,因为默认情况下函数是 const 的,要
 修改传递进来的拷贝,可以添加 mutable 修饰符。
 =,&a,&b。除 a 和 b 按引用进行传递外,其他参数都按值进行传递。
 &,a,b。除 a 和 b 按值进行传递外,其他参数都按引用进行传递。
14. Rvalue reference and Move Semantics 
  lvalue(locator value)代表一个在内存中占有确定位置的对象(换句话说就是有一个地址)。
 rvalue通过排他性来定义,每个表达式不是lvalue就是rvalue。因此从上面的lvalue的定义,rvalue是不在内存中占有确定位置的表达式。
 举例:理解C和C++中的左值和右值_xuwqiang1994的博客-CSDN博客 
    常量4和表达式var+1都不是lvalue(它们是rvalue)。它们不是lvalue,因为都是表达式的临时结果,没有确定的内存空间(换句话说,它们只是计算的周期驻留在临时的寄存器中)。因此给它们赋值没有语意-这里没有地方给它们赋值。
 foo返回一个临时的rvalue。尝试给它赋值,foo()=2,是一个错误;编译器期待在赋值运算符的左部分看到一个lvalue。
 不是所有的对函数调用结果赋值都是无效的。比如,C++的引用(reference)让这成为可能:
 const int a = 10; //‘a’是一个左值
 […] 一个左值没有数组类型,没有不完全类型,没有const修饰的类型,并且如果它是结构体或联合体,则没有任何const修饰的成员(包含,递归包含,任何成员元素的集合)。
 一个非函数,非数组类型的左值T可以被转换成一个右值。[…]如果T是一个非类类型,那么转换成的右值类型是T的非CV修饰版本。否则,那个右值类型是T。
 && 语法是新的右值引用。的确如它名字一样-给我们一个右值的引用,在调用之后将被析构。我们可以使用我们只是“偷”这个内部的右值这个事实-我们根本不需要它们!输出为:
代码: #include<iostream>
using namespace std;
class Intvec
{
public:
    explicit Intvec(size_t num = 0)
        : m_size(num), m_data(new int[m_size])
    {
        log("constructor");
    }
    ~Intvec()
    {
        log("destructor");
        if (m_data) {
            delete[] m_data;
            m_data = 0;
        }
    }
    Intvec(const Intvec& other)
        : m_size(other.m_size), m_data(new int[m_size])
    {
        log("copy constructor");
        for (size_t i = 0; i < m_size; ++i)
            m_data[i] = other.m_data[i];
    }
//    Intvec& operator=(const Intvec&& other)  // 执行v2 = v1;会报错 
    Intvec& operator=(const Intvec& other)
    {
        log("copy assignment operator");
        Intvec tmp(other);  // 函数执行完后, tmp会被释放掉 
        // other中的内容还在
        std::swap(m_size, tmp.m_size);   //由于other是常量类型,故不能调用std::swap(m_size, other.m_size);
        std::swap(m_data, tmp.m_data);
        return *this;
    }
    
    Intvec& operator=(Intvec&& other) // 将&&理解成偷 
	{
	    log("move assignment operator");
	    std::swap(m_size, other.m_size);
	    std::swap(m_data, other.m_data);
	    return *this;
	}
private:
    void log(const char* msg)
    {
        cout << "[" << this << "] " << msg << "\n";
    }
    size_t m_size;
    int* m_data;
};
int main() {
	Intvec v1(20);
	Intvec v2;
	
	cout << "assigning lvalue...\n";
//	v2 = v1;
	//  Intvec(33)构建了一个临时对象,执行完下面这一条语句,会被释放。 
	// Intvec& operator=(const Intvec& other), 里面要是const类型,不然如果不在写一个=重载函数,系统会说找不到=重载函数 
	//	或者写成 Intvec& operator=(Intvec&& other)  
	v2 = Intvec(33);    //系统调用的是Intvec& operator=(Intvec&& other)  
	
	cout << "ended assigning lvalue...\n";
	return 0;
}
15. Perfect Forwarding(完美传递) 
  
  顾名思义,完美转发是将参数不改变属性的条件下,转发给下一个函数. 因为普通函数的参数一旦具名,始终都是lvalue. 如果把rvalue转发到下一个函数上的参数中,还是rvalue(不会产生过多的内存)这就是完美转发的目的。
16. Move-aware class 
  17. Vector 
  
  18. Hashtable, Hast funciton 
  
  Hast funciton(系统会有一个计算hashcode的函数)
19. Tuple 
  
  参看2. Variadic Template代码。
 |