@@ -80,6 +80,18 @@ std::wstring utf8_to_wstring(std::string const &s) {
80
80
}
81
81
```
82
82
83
+ ## 读取整个文件到字符串
84
+
85
+ ``` cpp
86
+ TODO
87
+ ```
88
+
89
+ ## 位域(bit-field)
90
+
91
+ ``` cpp
92
+ TODO
93
+ ```
94
+
83
95
## 别再写构造函数啦!
84
96
85
97
``` cpp
@@ -874,7 +886,7 @@ int res = bound(5, 6); // 等价于 func(6, 1, 5, w);
874
886
875
887
这是一个绑定器,把 `func` 的第二个参数和第四个参数固定下来,形成一个新的函数对象,然后只需要传入前面两个参数就可以调用原来的函数了。
876
888
877
- 这是一个非常旧的技术,C++11 时代就有了。但是,现在有了 Lambda 表达式,可以更简洁地实现:
889
+ 这是一个非常旧的技术,C++98 时代就有了。但是,现在有了 Lambda 表达式,可以更简洁地实现:
878
890
879
891
```cpp
880
892
int func(int x, int y, int z, int &w);
@@ -898,6 +910,8 @@ Lambda 表达式有许多优势:
898
910
auto lambda = [&w](int x, int y) { return func(y + 8, 1, x * x, ++w) * 2; };
899
911
```
900
912
913
+ ### bind 的历史
914
+
901
915
为什么 C++11 有了 Lambda 表达式,还要提出 `std::bind` 呢?
902
916
903
917
虽然 bind 和 lambda 看似都是在 C++11 引入的,实际上 bind 的提出远远早于 lambda。
@@ -945,6 +959,8 @@ void some_func(int i1, int i2, int i3, int i4);
945
959
946
960
> {{ icon.fun }} 所以,现在还坚持用 bind 的,都是些 2005 年前后在象牙塔接受 C++ 教育,但又不肯“终身学习”的劳保。这批劳保又去“上岸”当“教师”,继续复制 2005 年的错误毒害青少年,实现了劳保的再生产。
947
961
962
+ ### thread 膝盖中箭
963
+
948
964
糟糕的是,bind 的这种荼毒,甚至影响到了线程库:` std::thread ` 的构造函数就是基于 ` std::bind ` 的!
949
965
950
966
这导致了 ` std::thread ` 和 ` std::bind ` 一样,无法捕获引用。
@@ -975,7 +991,7 @@ t.join();
975
991
printf("%d\n", x); // 42
976
992
```
977
993
978
- 最后再举个绑定随机数生成器例子:
994
+ ### 举个绑定随机数生成器例子
979
995
980
996
``` cpp
981
997
std::mt19937 gen (seed);
@@ -1049,7 +1065,7 @@ void some_func(auto &&arg) {
1049
1065
1050
1066
少了烦人的尖括号,看起来容易懂多了。
1051
1067
1052
- > {{ icon.tip }} 但是,这里有一个问题 ,为什么 `std::forward` 要写成 `std::forward<T>` 的形式呢?为什么不是 `std::forward(t)` 呢?因为这样写的话,`forward` 也没法知道你的 `t` 是左是右了(函数参数始终会默认推导为左,即使定义的 `t` 是右)因此必须告诉 `forward`,`t` 的定义类型,也就是 `T`,或者通过 `decltype(t)` 来获得 `T`。
1068
+ > {{ icon.detail }} 但是,我们同学有一个问题 ,为什么 `std::forward` 要写成 `std::forward<T>` 的形式呢?为什么不是 `std::forward(t)` 呢?因为这样写的话,`forward` 也没法知道你的 `t` 是左是右了(函数参数始终会默认推导为左,即使定义的 `t` 是右)因此必须告诉 `forward`,`t` 的定义类型,也就是 `T`,或者通过 `decltype(t)` 来获得 `T`。
1053
1069
1054
1070
总之,如果你用的是 `auto &&` 参数,那么 `FWD` 会很方便(自动帮你 `decltype`)。但是如果你用的是模板参数 `T &&`,那么 `FWD` 也可以用,因为 `decltype(t)` 总是得到 `T`。
1055
1071
@@ -1064,7 +1080,7 @@ struct Class {
1064
1080
}
1065
1081
1066
1082
void hello() {
1067
- auto memfn = std::bind(&Class::world, this); // 将 this->world 绑定成一个函数对象
1083
+ auto memfn = std::bind(&Class::world, this); // 将 this->world 绑定成一个可以延后调用的函数对象
1068
1084
memfn();
1069
1085
memfn();
1070
1086
}
@@ -1089,7 +1105,7 @@ struct Class {
1089
1105
}
1090
1106
```
1091
1107
1092
- 问题是 ,当我们的成员函数含有多个参数时,bind 就非常麻烦了, 需要一个个写出 placeholder,而且数量必须和 ` world ` 的参数数量一致。每次 ` world ` 要新增参数时,都需要加一下 placeholder,非常沙雕。
1108
+ bind 的缺点是 ,当我们的成员函数含有多个参数时,bind 就非常麻烦了: 需要一个个写出 placeholder,而且数量必须和 ` world ` 的参数数量一致。每次 ` world ` 要新增参数时,所有 bind 的地方都需要加一下 placeholder,非常沙雕。
1093
1109
1094
1110
``` cpp
1095
1111
struct Class {
@@ -1128,7 +1144,7 @@ struct Class {
1128
1144
}
1129
1145
```
1130
1146
1131
- 而 C++14 起 lambda 支持变长参数,就没有这么死板 :
1147
+ 而 C++14 起 lambda 支持了变长参数,就不用这么死板 :
1132
1148
1133
1149
``` cpp
1134
1150
struct Class {
@@ -1150,7 +1166,7 @@ struct Class {
1150
1166
}
1151
1167
```
1152
1168
1153
- 更好的是配合 ` FWD ` 宏实现参数的完美转发:
1169
+ 更好的是配合上文提到的 ` FWD ` 宏实现参数的完美转发:
1154
1170
1155
1171
``` cpp
1156
1172
struct Class {
@@ -1562,28 +1578,10 @@ if (auto it = table.find(key); it != table.end()) {
1562
1578
}
1563
1579
```
1564
1580
1565
- ## 检测是否存在指定成员函数
1566
-
1567
- TODO
1568
-
1569
- ## 位域(bit-field)
1570
-
1571
1581
## map + any 外挂属性
1572
1582
1573
- ## vector + unordered_map = LRU cache
1574
-
1575
- ## 多线程通信应基于队列,而不是共享全局变量
1576
-
1577
1583
## 自定义 shared_ptr 的 deleter
1578
1584
1579
- ## 读取整个文件
1580
-
1581
- ## RAII 的 finally
1582
-
1583
- ## swap 缩小 mutex 区间代价
1584
-
1585
- ## Lambda 捕获 unique_ptr 导致 function 报错怎么办
1586
-
1587
1585
## CHECK_CUDA 类错误检测宏
1588
1586
1589
1587
## 函数默认参数求值的位置是调用者
@@ -1593,32 +1591,13 @@ TODO
1593
1591
## 花括号实现安全的类型转换检查
1594
1592
1595
1593
## 成员函数针对 this 的移动重载
1596
- ## 位域(bit-field)
1597
-
1598
- ## vector + unordered_map = LRU cache
1599
-
1600
- ## 多线程通信应基于队列,而不是共享全局变量
1601
-
1602
- ## 自定义 shared_ptr 的 deleter
1603
-
1604
- ## 读取整个文件到字符串
1605
-
1606
- ## RAII 的 finally
1607
-
1608
- ## swap 缩小 mutex 区间代价
1609
-
1610
- ## Lambda 捕获 unique_ptr 导致 function 报错怎么办
1611
1594
1612
1595
## CHECK_CUDA 类错误检测宏
1613
1596
1614
1597
## 函数默认参数求值的位置是调用者
1615
1598
1616
- ## 设置 locale 为 .utf8
1617
-
1618
1599
## 花括号实现安全的类型转换检查
1619
1600
1620
- ## 成员函数针对 this 的移动重载
1621
-
1622
1601
## 临时右值转左值
1623
1602
1624
1603
C++ 有个特性:支持纯右值(prvalue)隐式转换成 const 的左值引用。
@@ -1671,10 +1650,24 @@ func(temporary(1));
1671
1650
1672
1651
> {{ icon.story }} 在 Libreoffice 源码中就有应用这个帮手函数。
1673
1652
1674
- ## 临时变量的生命周期是一行
1653
+ > {{ icon.warn }} 临时变量的生命周期是一行
1675
1654
1676
- TODO
1655
+ ## ADL 机制
1656
+
1657
+ ## shared_from_this
1658
+
1659
+ ## requires 语法检测是否存在指定成员函数
1677
1660
1678
- ### ADL 机制
1661
+ ## 设置 locale 为 .utf8 解决编码问题
1662
+
1663
+ ## 成员函数针对 this 的移动重载
1679
1664
1680
- ### `shared_from_this`
1665
+ <!-- ## vector + unordered_map = LRU cache -->
1666
+ <!-- -->
1667
+ <!-- ## Lambda 捕获 unique_ptr 导致 function 报错怎么办 -->
1668
+ <!-- -->
1669
+ <!-- ## 多线程通信应基于队列,而不是共享全局变量 -->
1670
+ <!-- -->
1671
+ <!-- ## RAII 的 finally -->
1672
+ <!-- -->
1673
+ <!-- ## swap 缩小 mutex 区间代价 -->
0 commit comments