|
@@ -0,0 +1,499 @@
|
|
|
|
|
+<!--
|
|
|
|
|
+ * @Author: your name
|
|
|
|
|
+ * @Date: 2021-10-21 10:56:48
|
|
|
|
|
+ * @LastEditTime: 2021-11-18 21:08:59
|
|
|
|
|
+ * @LastEditors: Please set LastEditors
|
|
|
|
|
+ * @FilePath: \MarkdownLog\cpp\C++11&14.md
|
|
|
|
|
+-->
|
|
|
|
|
+
|
|
|
|
|
+- C++的一些版本
|
|
|
|
|
+ - C++98(1.0)
|
|
|
|
|
+ - C++03
|
|
|
|
|
+ - C++11(2.0)
|
|
|
|
|
+ - C++14
|
|
|
|
|
+
|
|
|
|
|
+## Variadic Templates 可变参数模板
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+void printX()
|
|
|
|
|
+{}
|
|
|
|
|
+
|
|
|
|
|
+template <typename T, typename... Types>
|
|
|
|
|
+void printX(const T& firstArg, const Types&... args)
|
|
|
|
|
+{
|
|
|
|
|
+ cout << firstArg << endl;
|
|
|
|
|
+ printX(args...);
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 通过`sizeof...(args)`可以知道args中包括多少个参数
|
|
|
|
|
+
|
|
|
|
|
+通过可变参数模板,可以帮助我们使用递归做一些操作
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+// 可变参数模板的用例
|
|
|
|
|
+
|
|
|
|
|
+#include <functional>
|
|
|
|
|
+template<typename T>
|
|
|
|
|
+inline void hash_combine(size_t& seed. const T& val)// 函数_4
|
|
|
|
|
+{
|
|
|
|
|
+ seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed<<6) + (seed >> 2);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+template<typename T>
|
|
|
|
|
+inline void hash_val(size_t& seed, const T& val){// 函数_3
|
|
|
|
|
+ hash_combine(seed, val);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+template<typename T, typename... Types>
|
|
|
|
|
+inline void hash_val(size_t& seed, const T& val, const Types&... args)// 函数_2
|
|
|
|
|
+{
|
|
|
|
|
+ hash_combine(seed, val);
|
|
|
|
|
+ // 根据args...的参数个数来执行 函数_2 或者 函数_3
|
|
|
|
|
+ hash_val(seed, args... );
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+template<typename... Types>
|
|
|
|
|
+inline size_t hash_val(const Types&... args)// 函数_1
|
|
|
|
|
+{
|
|
|
|
|
+ size_t seed = 0;
|
|
|
|
|
+ // 虽然 函数_1 和 函数_2 都符合执行条件,但是 函数_2 相比而言更特化,所以执行 函数_2
|
|
|
|
|
+ hash_val(seed, args);
|
|
|
|
|
+ return seed;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+class CustomerHash{
|
|
|
|
|
+ public:
|
|
|
|
|
+ std::size_t operator()(const Customer& c) const{
|
|
|
|
|
+ // 因为第一个fname不是size_t类型,所以执行的是 函数_1 hash_val
|
|
|
|
|
+ return hash_val(c.fname, c.lname, c.no);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 这里用args配合递归不停的切分参数
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+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) {}
|
|
|
|
|
+ typename Head::type head() {return m_head;}
|
|
|
|
|
+ inherited& tail() {return *this;}
|
|
|
|
|
+
|
|
|
|
|
+protected:
|
|
|
|
|
+ Head m_head;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// tuple<int, float, string> t(41, 6.3, "Niko");
|
|
|
|
|
+// t.head() -> 41
|
|
|
|
|
+// t.tail() -> tuple<float, string>(6.3, "Niko")
|
|
|
|
|
+// t.tail()->head() -> 6.3
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 这里最上面有个空的 tuple<>,是作为递归继承的中止点
|
|
|
|
|
+> 这里用递归继承的方式做出了tuple
|
|
|
|
|
+
|
|
|
|
|
+## 模板中的空格
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+vector<list<int> > // 全版本支持
|
|
|
|
|
+vector<list<int>> // C++11之后没有空格也行
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 因为老版本一些编译器会将`>>`识别为操作符,所以需要加空格
|
|
|
|
|
+> C++11之后不加空格也行
|
|
|
|
|
+
|
|
|
|
|
+## nullptr ans std::nullptr_t
|
|
|
|
|
+
|
|
|
|
|
+`nullptr` 指的是 空指针,C++11允许用`nullptr`代替0或者`NULL`
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+void f(int);
|
|
|
|
|
+void f(void*);
|
|
|
|
|
+f(0); // 运行 f(int)
|
|
|
|
|
+f(NULL); // 运行 f(int),如果是其他数,就不清楚具体调用哪个了
|
|
|
|
|
+f(nullptr); // 云心 f(void*)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+#if defined(__cplusplus) && __cplusplus >= 201103L
|
|
|
|
|
+#ifndef __GXX_NULLPTR_T
|
|
|
|
|
+#define __GXX_NULLPTR_T
|
|
|
|
|
+ typedef decltype(nullptr) nullptr_t;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## auto
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+auto i = 20; // i 的 类型是 int
|
|
|
|
|
+
|
|
|
|
|
+double f();
|
|
|
|
|
+auto d = f(); // d 的 类型是 double
|
|
|
|
|
+
|
|
|
|
|
+vector<string> v;
|
|
|
|
|
+auto pos = v.begin(); // pos 的 类型是 vector<string>::iterator
|
|
|
|
|
+
|
|
|
|
|
+auto l = [](int x) -> bool {
|
|
|
|
|
+ // ...
|
|
|
|
|
+}; // l 的类型是 lambda表达式
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 使用`auto`主要是用在数据类型 **太长** 或者 **太复杂** 的情况 (比如迭代器、lambda的类型)
|
|
|
|
|
+> 倒也不是什么情况都用`auto`
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+// 标准库中对auto的使用
|
|
|
|
|
+#if __cplusplus >= 201103L
|
|
|
|
|
+ inline auto operator- (const reverse_iterator<_IteratorL> &__x,
|
|
|
|
|
+ const reverse_iterator<_IteratorR> &__y)
|
|
|
|
|
+ -> decltype(__y.base() - __x.base())
|
|
|
|
|
+#else
|
|
|
|
|
+ inline typename reverse_iterator<_IteratorL>::difference_type
|
|
|
|
|
+ operator- (const reverse_iterator<_IteratorL>& __x,
|
|
|
|
|
+ const reverse_iteratror<_IteratorR>& __y)
|
|
|
|
|
+#endif
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## unifor initialization 一致性初始化
|
|
|
|
|
+
|
|
|
|
|
+初始化可能发生在小括号、中括号、赋值中
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+Rect r1 = {3, 4, 5}; // 大括号
|
|
|
|
|
+Rect r1(3, 4, 5); // 小括号
|
|
|
|
|
+int values[5] = {1, 3, 4, 5}; // 赋值
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+C++11引入**一致性初始化**——大括号(虽然用以前的也没错)
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+int values[]{1, 3, 4, 5};
|
|
|
|
|
+vector<int> v{1, 3 ,4 ,5};
|
|
|
|
|
+complex<duoble> c{3.0, 4.0};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 变量之后直接加上大括号即表示初始化
|
|
|
|
|
+
|
|
|
|
|
+当编译器看到`{t1, t2, t3...}`便做出一个`initializer_list<T>`,他关联至一个`array<T, n>`,调用函数(比如构造函数)时`arry`中的元素被逐个分解传给函数;如果调用函数的参数就是`initializer_list<T>`,就不会注意分解而是直接整个传给函数
|
|
|
|
|
+
|
|
|
|
|
+比如:`vector<int> v{1, 3 ,4 ,5};` 中的初始化参数 `{1, 3 ,4 ,5}`转换成 `initlializer_list<int>`,而这个关联`array<int, 4>`容器
|
|
|
|
|
+
|
|
|
|
|
+## initalizer_list 初始化列表
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+int i; // 没有被初始化
|
|
|
|
|
+int j{}; // j被初始化为0
|
|
|
|
|
+int *p; // p没有被初始化
|
|
|
|
|
+int *q{}; // q被初始化为nullptr
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+int x1(4.3); // ok
|
|
|
|
|
+int x2 = 4.3; // ok
|
|
|
|
|
+int x3 {4.3}; // 部分平台Error,部分平台warning
|
|
|
|
|
+int x4 = {5.3}; // 部分平台Error,部分平台warning
|
|
|
|
|
+
|
|
|
|
|
+char c1{7}; // ok
|
|
|
|
|
+char c2{9999}; // 部分平台Error,部分平台warning
|
|
|
|
|
+
|
|
|
|
|
+std::vector<int> v1{1, 3, 4, 5}; // ok
|
|
|
|
|
+std::vector<int> v2{1.0, 3.0, 4.0, 5.0}; // 部分平台Error,部分平台warning
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 初始化列表的作用,还可以帮助检查一些错误
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+
|
|
|
|
|
+void print(std::initlializer_list<int> vals)
|
|
|
|
|
+{
|
|
|
|
|
+ for(auto p = vals.begin(), p != vals.end(); ++p){
|
|
|
|
|
+ std::cout << *p << std::endl;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+print({1, 3, 4, 5});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 证明`{t1, t2, t3...}`被转换成`initializer_list<T>`
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+class P{
|
|
|
|
|
+public:
|
|
|
|
|
+ P(int a, int b){
|
|
|
|
|
+ std::cout << "(int ,int)" << std::endl;
|
|
|
|
|
+ }
|
|
|
|
|
+ P(initializer_list<int> initlist){
|
|
|
|
|
+ std::cout << "initializer_list" << std::endl;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+P p(7, 7); // 输出 (int ,int)
|
|
|
|
|
+P p{7, 7}; // 输出 initializer_list
|
|
|
|
|
+P r{7, 5, 4}; // 输出 initializer_list
|
|
|
|
|
+P p = {7, 7}; // 输出 initializer_list
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 如果不存在第二个`initializer_list`的构造函数,则第三个对象 r 将创建失败
|
|
|
|
|
+
|
|
|
|
|
+## explicit
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * non-explicit-one-argument 只要一个实参就够了的构造函数
|
|
|
|
|
+ * 下面例子中:没有写oprator * (Fraction, int)的操作符重载也不会报错,因为编译器将4通过一个参数的构造变成Fraction(4, 1)类型
|
|
|
|
|
+ * 当构造函数前加上explicit关键字时,编译器不会进行隐式构造函数将4变成Fraction(4, 1)
|
|
|
|
|
+ *
|
|
|
|
|
+ * ——————————————————————————————————————————————————————————————————————————————
|
|
|
|
|
+ * 如果构造函数不存在explicit,且有operator double()转换函数,编译器报错,因为存在二义性即两种方式都可以行得通且没有优先级这么一说
|
|
|
|
|
+ * 如果构造函数存在explicit,且有operator double()转换函数,编译器不报错,因为只有一条路可走,将Fraction转换成double计算
|
|
|
|
|
+ * 如果构造函数不存在explicit,且没有operator double()转换函数,编译器不报错,因为只有一条路可走,将4转换成Fraction计算
|
|
|
|
|
+ **/
|
|
|
|
|
+
|
|
|
|
|
+class Fraction
|
|
|
|
|
+{
|
|
|
|
|
+ public:
|
|
|
|
|
+ // 这里构造函数只需要一个参数其实也够
|
|
|
|
|
+ Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den) {}
|
|
|
|
|
+ //explicit Fraction(int num, int den = 1) : m_numerator(num), m_denominator(den) {}
|
|
|
|
|
+
|
|
|
|
|
+ Fraction operator*(const Fraction &f)
|
|
|
|
|
+ {
|
|
|
|
|
+ return Fraction(f.m_numerator * this->m_numerator, f.m_denominator * this->m_denominator);
|
|
|
|
|
+ }
|
|
|
|
|
+ std::string getString()
|
|
|
|
|
+ {
|
|
|
|
|
+ char numerator[10];
|
|
|
|
|
+ char denominator[10];
|
|
|
|
|
+ memset(numerator, 0, sizeof(numerator));
|
|
|
|
|
+ memset(denominator, 0, sizeof(denominator));
|
|
|
|
|
+ itoa(m_numerator, numerator, 10);
|
|
|
|
|
+ itoa(m_denominator, denominator, 10);
|
|
|
|
|
+ return std::string(std::string(numerator) + std::string("/") + std::string(denominator));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private:
|
|
|
|
|
+ int m_denominator; // 分母
|
|
|
|
|
+ int m_numerator; // 分子
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+int main()
|
|
|
|
|
+{
|
|
|
|
|
+ Fraction f(3, 5);
|
|
|
|
|
+ Fraction f2 = f * 4;
|
|
|
|
|
+ std::cout << f2.getString() << std::endl;
|
|
|
|
|
+ system("pause");
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> explicit告诉编译器,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换
|
|
|
|
|
+
|
|
|
|
|
+## range-based for statement
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+// for(decl : coll){
|
|
|
|
|
+// statement
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
|
|
+for(int i : {2, 3, 4, 5, 6}){
|
|
|
|
|
+ cout << i << endl;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+vector<double> vec;
|
|
|
|
|
+//...
|
|
|
|
|
+for(auto elem : vec){
|
|
|
|
|
+ cout << elem << endl;
|
|
|
|
|
+}
|
|
|
|
|
+for(auto &elem : vec){
|
|
|
|
|
+ elem *= 3;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// range-based for 的底层实现类似
|
|
|
|
|
+
|
|
|
|
|
+for(auto _pos = coll.begin(), _end = coll.end(); _pos != _end; ++pos){
|
|
|
|
|
+ decl = *_pos;
|
|
|
|
|
+ // 对值的操作
|
|
|
|
|
+}
|
|
|
|
|
+// 或者
|
|
|
|
|
+for(auto _pos = begin(coll), _end = end(coll); _pos != _end; ++pos){
|
|
|
|
|
+ decl = *_pos;
|
|
|
|
|
+ // 对值的操作
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**下面的写法会报错**
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+class C{
|
|
|
|
|
+public:
|
|
|
|
|
+ explicit C(const string& s); // 禁止string隐式转换成C
|
|
|
|
|
+ // ...
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+vector<string> vs;
|
|
|
|
|
+for(const C& elem : vs){
|
|
|
|
|
+ cout << elem << endl; // 报错,因为字符串不能隐式的转换成C
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## =default, =delete
|
|
|
|
|
+
|
|
|
|
|
+如果自行定义一个构造函数,那么编译器不会再给一个默认构造函数
|
|
|
|
|
+
|
|
|
|
|
+如果强制加上 `=default` 就可以重新获得并使用默认构造函数
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+class Zoo
|
|
|
|
|
+{
|
|
|
|
|
+public:
|
|
|
|
|
+ Zoo(int i1, int i2) : d1(i1), d2(i2) {}
|
|
|
|
|
+ Zoo(const Zoo&) =delete; // 不允许拷贝构造
|
|
|
|
|
+ Zoo(Zoo &&) =default; // 使用编译器给的
|
|
|
|
|
+ Zoo& operator=(const Zoo &) =default;
|
|
|
|
|
+ Zoo& operator=(const Zoo&&) =delete;
|
|
|
|
|
+ virtual ~Zoo(){}
|
|
|
|
|
+private:
|
|
|
|
|
+ int d1, d2;
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+class Foo{
|
|
|
|
|
+public:
|
|
|
|
|
+ Foo(int i) : _i(i) {}
|
|
|
|
|
+ Foo() = default; // 构造函数可以有多个,这里希望编译器提供默认构造
|
|
|
|
|
+
|
|
|
|
|
+ Foo(const Foo& x) : _i(x._i) {}
|
|
|
|
|
+ // Foo(const Foo&) = default; // Error 拷贝构造函数不可被重载
|
|
|
|
|
+ // Foo(const Foo&) = delete; // Error 拷贝构造函数不可被重载
|
|
|
|
|
+
|
|
|
|
|
+ Foo& operator=(const Foo& x) {_i = x._i; return *this;}
|
|
|
|
|
+ // Foo& operator=(const Foo& x) = default; // Error 赋值不可被重载
|
|
|
|
|
+ // Foo& operator=(const Foo& x) = delete; // Error 赋值不可被重载
|
|
|
|
|
+
|
|
|
|
|
+ void func1() = default; // Error 不可作为default
|
|
|
|
|
+ void func2() = delete; // ok 不过如果不需要可以不写这个函数…
|
|
|
|
|
+
|
|
|
|
|
+ ~Foo() = default;
|
|
|
|
|
+ // ~Foo() = delete // 可以new不可delete
|
|
|
|
|
+};
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+- `=default` 除了默认成员函数(构造、析构、拷贝、赋值等)之外,其他函数使用编译报错(很明显,其他函数也没有所谓的默认)
|
|
|
|
|
+- `=delete`可以用在任何函数上(`=0`只能用于`virtual`函数)
|
|
|
|
|
+
|
|
|
|
|
+> 一般而言,如果成员对象中存在指针,建议考虑深拷贝、浅拷贝的问题,需要自定义拷贝、赋值函数
|
|
|
|
|
+
|
|
|
|
|
+## Alias Templat (template typedef)化名模板
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+template<typename T>
|
|
|
|
|
+using Vec = std::vector<T, MyAlloc<T>>;
|
|
|
|
|
+
|
|
|
|
|
+Vec<int> coll; // = std::vector<int, MyAlloc<int> coll;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## decltype
|
|
|
|
|
+
|
|
|
|
|
+使用该关键字可以找到表达式的参数类型
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+map<string, float> coll;
|
|
|
|
|
+decltype(coll)::value_type elem; // C++11可以通过对象使用
|
|
|
|
|
+map<string,float>::value_type elem; // C++11之前必须指明类型使用
|
|
|
|
|
+
|
|
|
|
|
+template<typename T1, typename T2>
|
|
|
|
|
+auto add(T1 x, T2 y) -> decltype(x+y); // 通过decltype动态设置返回参数类型
|
|
|
|
|
+
|
|
|
|
|
+decltype(x+y) add(T1 x, T2 y); // 这样写报错,因为decltype先不知道x、y是什么,在后面的函数参数中才知道
|
|
|
|
|
+
|
|
|
|
|
+auto cmp = [](const Person& p1, const Person& p2){
|
|
|
|
|
+ // 比较大小
|
|
|
|
|
+};
|
|
|
|
|
+std::set<Person, decltype(cmp)> coll(cmp);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## lambda表达式
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+[]{
|
|
|
|
|
+ std::cout << "hello world" << std::endl;
|
|
|
|
|
+}(); // 输出 hello world
|
|
|
|
|
+
|
|
|
|
|
+auto l = []{
|
|
|
|
|
+ std::cout << "hello world" << std::endl;
|
|
|
|
|
+};
|
|
|
|
|
+l();// 输出 hello world
|
|
|
|
|
+
|
|
|
|
|
+[导入器](参数) mutable 异常 -> 返回类型 {
|
|
|
|
|
+ 函数体
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 导入器,取用的外部变量(传值、传引用)
|
|
|
|
|
+> 参数,正常函数参数
|
|
|
|
|
+> mutable 是否可以修改值
|
|
|
|
|
+> 异常 一些特殊操作抛出异常
|
|
|
|
|
+
|
|
|
|
|
+```cpp
|
|
|
|
|
+{
|
|
|
|
|
+ int id = 0;
|
|
|
|
|
+ // 值传递
|
|
|
|
|
+ auto f = [id]() mutable {
|
|
|
|
|
+ std::cout << "id : " << id << std::endl;
|
|
|
|
|
+ ++id;// 如果没有mutable,则id不可执行++操作
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ id = 42;
|
|
|
|
|
+ f(); // 输出 id : 0
|
|
|
|
|
+ f(); // 输出 id : 1
|
|
|
|
|
+ f(); // 输出 id : 2
|
|
|
|
|
+ std::cout << id << std::endl; // 输出 id : 42
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+{
|
|
|
|
|
+ int id = 0;
|
|
|
|
|
+ // 引用传递
|
|
|
|
|
+ auto f = [&id](int param) {
|
|
|
|
|
+ std::cout << "id : " << id << std::endl;
|
|
|
|
|
+ ++id; ++param;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ id = 42;
|
|
|
|
|
+ f(7); // 输出 id : 42
|
|
|
|
|
+ f(7); // 输出 id : 43
|
|
|
|
|
+ f(7); // 输出 id : 44
|
|
|
|
|
+ std::cout << id << std::endl; // 输出 id : 45
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+{
|
|
|
|
|
+ int id = 0;
|
|
|
|
|
+ auto f = [id]() {
|
|
|
|
|
+ std::cout << "id : " << id << std::endl;
|
|
|
|
|
+ ++id;
|
|
|
|
|
+ };
|
|
|
|
|
+ // 报错 没有mutable 不可更改
|
|
|
|
|
+ id = 42;
|
|
|
|
|
+ f();
|
|
|
|
|
+ f();
|
|
|
|
|
+ f();
|
|
|
|
|
+ std::cout << id << std::endl;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 一个 = 表示 其他所有对象都是值传递, id为引用传递
|
|
|
|
|
+auto f = [=, &id]{
|
|
|
|
|
+ // ...
|
|
|
|
|
+};
|
|
|
|
|
+```
|